Многократные цепные розыгрыши для простого многовариантного вывода Бернулли - PullRequest
1 голос
/ 10 октября 2019

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

Возвращенная ошибка: ValueError: Dimension must be 3 but is 2 for 'mcmc_sample_chain/simple_step_size_adaptation___init__/_bootstrap_results/mh_bootstrap_results/hmc_kernel_bootstrap_results/maybe_call_fn_and_grads/value_and_gradients/mcmc_sample_chain_simple_step_size_adaptation___init____bootstrap_results_mh_bootstrap_results_hmc_kernel_bootstrap_results_maybe_call_fn_and_grads_value_and_gradients_Samplemcmc_sample_chain_simple_step_size_adaptation___init____bootstrap_results_mh_bootstrap_results_hmc_kernel_bootstrap_results_maybe_call_fn_and_grads_value_and_gradients_Independentmcmc_sample_chain_simple_step_size_adaptation___init____bootstrap_results_mh_bootstrap_results_hmc_kernel_bootstrap_results_maybe_call_fn_and_grads_value_and_gradients_Bernoulli/log_prob/transpose' (op: 'Transpose') with input shapes: [1,5000,2], [2].

Вот простой пример с D = 2 и N = 5000 (количество выборок вобучающий набор).

import numpy as np 
import tensorflow as tf
import tensorflow_probability as tfp
import functools
tfd = tfp.distributions

# ---------- DATA Generator ------------#

def generate_bernouilli(N,p):
    return np.array([np.random.binomial(size=N, n=1, p = probability) for probability in p ]).T

D = 2
N = 5000
p = np.sort(np.random.random(D))

observations = generate_bernouilli(N,p)

# ---------- Model ------------#

def make_likelihood(theta):
    one_y = tfd.Independent(
        distribution = tfd.Bernoulli(probs=theta),
        reinterpreted_batch_ndims=1)
    y = tfd.Sample(one_y,
          sample_shape=(N,))
    return y

def joint_log_prob(observations, theta):
    return (tf.reduce_sum(make_likelihood(theta).log_prob(observations)))

posterior_log_prob = functools.partial(joint_log_prob, observations)


# ---------- MCMC sampling  ------------#

num_results = int(10e3)
num_burnin_steps = int(1e3)
n_chains = 5

adaptive_hmc = tfp.mcmc.SimpleStepSizeAdaptation(
    tfp.mcmc.HamiltonianMonteCarlo(
        target_log_prob_fn=posterior_log_prob,
        num_leapfrog_steps=3,
        step_size=1.),
    target_accept_prob=tf.constant(.8),
    num_adaptation_steps=int(num_burnin_steps * 0.8))


@tf.function
def run_chain():
# Run the chain (with burn-in).
    samples, is_accepted = tfp.mcmc.sample_chain(
    num_results=num_results,
    num_burnin_steps=num_burnin_steps,
    current_state=tf.ones([n_chains,2])/10,
    kernel=adaptive_hmc,
    trace_fn=lambda _, pkr: pkr.inner_results.is_accepted)

    is_accepted = tf.reduce_mean(tf.cast(is_accepted, dtype=tf.float32))
    return samples, is_accepted


# ---------- Run  ------------#
with tf.device('/CPU:0'):
    samples, is_accepted = run_chain()

Код работает отлично, если мы заменим current_state на current_state=tf.ones([2])/10 (и, таким образом, удалим независимую цепную выборку.

У меня есть несколько вопросов, и я буду оченьблагодарен за любую помощь: + Правильно ли реализована моя модель? + Есть ли способ отладки этого типа ошибки в tf? Отладчик python не очень помогает.

Заранее спасибо!

1 Ответ

0 голосов
/ 26 октября 2019

Прежде всего, я явно не эксперт в вероятности тензорного потока, поэтому этот ответ, скорее всего, не будет наилучшей практикой, я просто заставил его работать с ограниченными знаниями в библиотеке, пытаясь узнать больше о вероятности тензорного потокасебя.

Во-вторых, я всего лишь хочу ответить на часть вопроса, касающегося модели и ее реализации, на ответ об отладке tenorflow, либо немного погуглите об этом, чтобы увидеть, есть ли какие-то учебники по этому вопросу,задайте другой вопрос, поскольку я чувствую, что это совсем другой вопрос.

Что касается модели, то она выглядит правильно реализованной, и я смог заставить ее работать без особых изменений, однако я бы порекомендовал явно использовать предшествующий theta по двум причинам. Во-первых, даже если вы не установите его, используется априор (в общем, униформа, которая является константой, в данном случае, безусловно, униформа априора и неограниченный униформ априор), и вы можете не знать, какой онили вы используете модель, отличную от реализованной. Во-вторых, вы можете столкнуться с неожиданными проблемами, когда используете предыдущую версию, не подходящую для данной проблемы. Например, здесь theta - это вектор измерения D, который должен быть между 0 и 1, однако в вашей реализации theta может принимать значения вне этого диапазона;к счастью, если параметр tfd.Bernoulli находится за пределами (0,1) тензор потока просто возвращает nan, но это может не всегда иметь место, это может привести к ошибке (которая будет срабатывать при random итерации, где тэта находится за пределами (0,1)), или вы можете просто получить непонятные результаты, где вероятность голов составляет 1.3.

Таким образом, я добавил априор и изменил следующие пункты кода:

  • Я добавил дополнительное измерение к observations, чтобы оно могло быть правильно передано
  • Я использовал distribution.log_prob() вместо log_prob из tfd.Sample. Я пытался использовать log_prob напрямую, но мне трудно понять, как tfd.Sample работает и как это влияет на log_prog исходного дистрибутива, поэтому я согласился с тем, что знаю лучше.
  • Я установилось до tf.reduce_sum. Это не дало никакой ошибки, потому что log_prob было выполнено раньше и не удалось, но это произошло бы потому, что при использовании нескольких цепочек каждая цепочка независима, поэтому каждая цепочка имеет свою логарифмическую вероятностную вероятность. posterior_log_prob должен возвращать тензор длины n_chains, больше не скаляр.

Вот полученный код, исключающий неизмененные части:

observations = generate_bernouilli(N,p)[:, None, :]

# ---------- Model ------------#

def make_prior(D):
    one_theta = tfd.Independent(
        distribution=tfd.Uniform(low=tf.zeros(D)),
        reinterpreted_batch_ndims=1
    )
    return one_theta

def make_likelihood(theta):
    one_y = tfd.Independent(
        distribution = tfd.Bernoulli(probs=theta),
        reinterpreted_batch_ndims=1
    )
    y = tfd.Sample(
          one_y,
          sample_shape=(N,)
    )
    return y

def joint_log_prob(observations, D, theta):
    return (
        make_prior(D).log_prob(theta) + 
        tf.reduce_sum(
            make_likelihood(theta).distribution.log_prob(observations), 
            axis=0
        )
    )

posterior_log_prob = functools.partial(joint_log_prob, observations, D)

# Small comment, for coherence I would also modify the following line
current_state=tf.ones([n_chains,D])/10, 
# otherwise, D != 2 would not work
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...