具有Tensorflow概率的贝叶斯线性回归

时间:2019-12-17 09:35:12

标签: python tensorflow bayesian tensorflow-probability

我无法使贝叶斯线性回归与Tensorflow概率一起使用。这是我的代码:

func showOptions(sender: AnyObject) {
    let alertController = UIAlertController.init(title: "Choose Option", message: "", preferredStyle: .actionSheet)
    let cameraAction = UIAlertAction.init(title: "Camera", style: .default) { (action) in
        self.selectImageFrom(.camera)
    }
    alertController.addAction(cameraAction)
    let photoLibraryAction = UIAlertAction.init(title: "Photo Library", style: .default) { (action) in
        self.selectImageFrom(.photoLibrary)
    }
    alertController.addAction(photoLibraryAction)
    let cancelAction = UIAlertAction.init(title: "Cancel", style: .cancel) { (action) in
    }
    alertController.addAction(cancelAction)
    present(alertController, animated: true, completion: nil)
}

enter image description here

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

令人惊讶的是,如此简单的问题有多难!原始HMC在设置推理时可能对相对较小的细节非常敏感。像Stan这样的系统会尝试通过为您做很多调整来解决这个问题,但是到目前为止,TFP的自动调整已变得更加基础。

我发现一些更改似乎在这里使推理工作正常。简而言之,它们是:

  • 在不受限制的空间中重新参数化。
  • 使用不均匀的步长(等同:添加对角前置条件器)
  • 增加HMC跳过步骤的数量。
  • 使用DualAveragingStepSizeAdaptation代替SimpleStepSizeAdaptation

第一个技巧是使用TransformedTransitionKernel重新参数化,以便scale参数位于不受限制的空间中。例如,我们可以使用Exp双射器来定义对数比例参数:

tfb = tfp.bijectors
kernel = tfp.mcmc.TransformedTransitionKernel(
      inner_kernel=kernel,
      bijector=[tfb.Identity(), tfb.Identity(), tfb.Exp()]
  )

这可以确保推理仅考虑刻度的正值,因此不必拒绝使刻度小于零的所有动作。当我这样做时,尽管混合效果仍然不佳,但接受率却上升了。

第二个更改是对三个变量使用非均匀步长(这等效于对角线预处理)。看起来此模型中的后验条件不佳:二十个数据点确定斜率 much 比确定截距或比例更精确。 TFP中的“步长调整”只是找到一个步长,以使指定百分比的样本可以被接受,这通常由后验中受最严格约束的分量控制:如果其他分量具有更宽的后验,则小步长将阻止他们从混合。估算合理步长的一种方法是,使用因变量推断的标准偏差和正态替代后验因子:

surrogate_posterior = tfp.experimental.vi.build_factored_surrogate_posterior(
    event_shape=[[], [], []],
    constraining_bijectors=[None, None, tfb.Exp()])
losses = tfp.vi.fit_surrogate_posterior(
    target_log_prob_fn, surrogate_posterior,
    optimizer=tf.optimizers.Adam(
        learning_rate=0.1,
        # Decay second-moment estimates to aid optimizing scale parameters.
        beta_2=0.9),
    num_steps=1000)
approximate_posterior_stddevs = [np.std(x) for x in surrogate_posterior.sample(50)]

另一个通用技巧是增加越级步数。思考HMC的一种方法是,在跨越式集成器中,它类似于具有动量的优化器,但是每次停止接受/拒绝时,它都会失去动量(通过重新采样)。因此,在极端情况下,我们每一个步骤(num_leapfrog_steps=1,即Langevin动力学)都没有动量,增加跳越步数往往会提高导航棘手几何形状的能力,类似于动量改进优化器。我没有严格调整任何内容,但是在此设置num_leapfrog_steps=16而不是3似乎​​很有帮助。

这是我的代码修改版,其中包含了这些技巧。在大多数执行中,它似乎混合得很好(尽管我确定它并不完美):

!pip install tensorflow==2.0.0-rc1
!pip install tensorflow-probability==0.8.0rc0

import numpy as np
import tensorflow as tf
import tensorflow_probability as tfp

tfd = tfp.distributions
tfb = tfp.bijectors

N = 20
std = 1
m = np.random.normal(0, scale=5, size=1).astype(np.float32)
b = np.random.normal(0, scale=5, size=1).astype(np.float32)
x = np.linspace(0, 100, N).astype(np.float32)
y = m*x+b+ np.random.normal(loc=0, scale=std, size=N).astype(np.float32)

num_results = 1000
num_burnin_steps = 500

def joint_log_prob(x, y, m, b, std):
  rv_m = tfd.Normal(loc=0, scale=5)
  rv_b = tfd.Normal(loc=0, scale=5)
  rv_std = tfd.HalfCauchy(0., scale=1.)

  y_mu = m*x+b
  rv_y = tfd.Normal(loc=y_mu, scale=rv_std[..., None])

  return (rv_m.log_prob(m) + rv_b.log_prob(b)
          + rv_std.log_prob(std)
          + tf.reduce_sum(rv_y.log_prob(y)))

# Define a closure over our joint_log_prob.
def target_log_prob_fn(m, b, std):
    return joint_log_prob(x, y, m, b, std)

# Run variational inference to initialize per-variable step sizes.
surrogate_posterior = tfp.experimental.vi.build_factored_surrogate_posterior(
    event_shape=[[], [], []],
    constraining_bijectors=[None, None, tfb.Exp()])
losses = tfp.vi.fit_surrogate_posterior(
    target_log_prob_fn,
    surrogate_posterior,
    optimizer=tf.optimizers.Adam(
        learning_rate=0.1,
        # Decay second-moment estimates to aid optimizing scale parameters.
        beta_2=0.9),
    num_steps=1000)
approximate_posterior_stddevs = [np.std(z) for z in surrogate_posterior.sample(50)]

@tf.function(autograph=False)
def do_sampling():
  kernel=tfp.mcmc.HamiltonianMonteCarlo(
          target_log_prob_fn=target_log_prob_fn,
          step_size=approximate_posterior_stddevs,
          num_leapfrog_steps=16)
  kernel = tfp.mcmc.TransformedTransitionKernel(
      inner_kernel=kernel,
      bijector=[tfb.Identity(),
                tfb.Identity(),
                tfb.Exp()]
  )
  kernel = tfp.mcmc.DualAveragingStepSizeAdaptation(
        inner_kernel=kernel,
        num_adaptation_steps=int(num_burnin_steps * 0.8))
  return tfp.mcmc.sample_chain(
      num_results=num_results,
      num_burnin_steps=num_burnin_steps,
      current_state=[
          0.01 * tf.ones([], name='init_m', dtype=tf.float32),
          0.01 * tf.ones([], name='init_b', dtype=tf.float32),
          1. * tf.ones([], name='init_std', dtype=tf.float32)
      ],
      kernel=kernel,
      trace_fn=lambda _, pkr: [pkr.inner_results.inner_results.accepted_results.step_size,
                               pkr.inner_results.inner_results.log_accept_ratio])

samples, [step_size, log_accept_ratio] = do_sampling()
m_posterior, b_posterior, std_posterior = samples

p_accept = tf.reduce_mean(tf.exp(tf.minimum(log_accept_ratio, 0.)))
print('Acceptance rate: {}'.format(p_accept))

n_v = len(samples)
true_values = [m, b, std]

plt.figure(figsize=(12, 12))
plt.title('Visualizing trace and posterior distributions')
for i, (sample, true_value) in enumerate(zip(samples, true_values)):
  plt.subplot(2*n_v, 2, 2*i+1)
  plt.plot(sample)
  plt.subplot(2*n_v, 2, 2*i+2)
  plt.hist(sample.numpy())
  plt.axvline(x=true_value)

答案 1 :(得分:1)

首先,提出的问题非常好-我很容易复制/粘贴您的代码并进行复制:)

第一个问题(与HMC一样)是step_size / num_leapfrog_steps设置。通过减小步长(〜.007)和减小越级步长(〜3),可以得到不错的接受率(〜.7)。通常,您希望将越级越步越小越好,因为每一次步阶都会导致昂贵的梯度计算。

下一个问题是,看起来这些链仍然没有很好地与这些参数混合。我怀疑这可能是居中与非居中(请参阅https://discourse.mc-stan.org/t/centered-vs-noncentered/1502)参数化的问题;您可能会更幸运地更改模型的参数化,尽管我对这个细节并不十分熟悉...

出于自动查找更好的步长参数的目的,您可以尝试使用2个步长自适应内核之一-SimpleStepSizeAdaptation或DualAveragingStepSizeAdaptation-可以将其包装在HMC内核实例周围。此外,您可以尝试使用NoUTurnSampler作为香草HMC的替代方法,以避免必须调整跳越步骤参数。对于一个简单的贝叶斯线性回归示例,所有这些都是相当沉重的,但是我想这个示例突出了正确实现MCMC的难度:)

希望这会有所帮助!随时通过tfprobability@tensorflow.org与我们联系以进行更多讨论-也许其他一些对参数化问题有更多了解的人也会加入。再次感谢您提出的重大问题。