【问题标题】:Constructing discrete table-based CPDs in tensorflow-probablity?在张量流概率中构建基于离散表的 CPD?
【发布时间】:2019-05-23 08:40:18
【问题描述】:

我正在尝试构建具有多个离散随机变量和条件概率的贝叶斯网络的最简单示例(Koller 书中的“学生网络”,参见 1

虽然有点笨拙,但我还是设法使用 pymc3 构建了这个网络。特别是,在 pymc3 中创建 CPD 并不是那么简单,请参见下面的 sn-p:

import pymc3 as pm

...

with pm.Model() as basic_model:
    # parameters for categorical are indexed as [0, 1, 2, ...]
    difficulty = pm.Categorical(name='difficulty', p=[0.6, 0.4])

    intelligence = pm.Categorical(name='intelligence', p=[0.7, 0.3])

    grade = pm.Categorical(name='grade',
        p=pm.math.switch(
            theano.tensor.eq(intelligence, 0),
                pm.math.switch(
                    theano.tensor.eq(difficulty, 0),
                        [0.3, 0.4, 0.3],  # I=0, D=0
                        [0.05, 0.25, 0.7]   # I=0, D=1
                    ),
                    pm.math.switch(
                        theano.tensor.eq(difficulty, 0),
                            [0.9, 0.08, 0.02],  # I=1, D=0
                            [0.5, 0.3, 0.2]  # I=1, D=1
                    )
            )
        )

    letter = pm.Categorical(name='letter', p=pm.math.switch(
    ...

但我不知道如何使用 tensoflow-probability 构建这个网络(版本:tfp-nightly==0.7.0.dev20190517tf-nightly-2.0-preview==2.0.0.dev20190517

对于无条件的二元变量,可以使用分类分布,比如

from tensorflow_probability import distributions as tfd
from tensorflow_probability import edward2 as ed

difficulty = ed.RandomVariable(
                 tfd.Categorical(
                     probs=[0.6, 0.4],
                     name='difficulty'
                 )
             )

但是如何构建 CPD?

tensorflow-probability 中可能相关的类/方法很少(在 tensorflow_probability/python/distributions/deterministic.py 或已弃用的 ConditionalDistribution 中),但文档相当稀少(需要深入了解 tfp)。

--- 更新问题---

克里斯的回答是一个很好的起点。然而,即使对于一个非常简单的二变量模型,事情仍然有些不清楚。

这很好用:

jdn = tfd.JointDistributionNamed(dict(
    dist_x=tfd.Categorical([0.2, 0.8], validate_args=True),
    dist_y=lambda dist_x: tfd.Bernoulli(probs=tf.gather([0.1, 0.9], indices=dist_x), validate_args=True)
))
print(jdn.sample(10))

但是这个失败了

jdn = tfd.JointDistributionNamed(dict(
    dist_x=tfd.Categorical([0.2, 0.8], validate_args=True),
    dist_y=lambda dist_x: tfd.Categorical(probs=tf.gather_nd([[0.1, 0.9], [0.5, 0.5]], indices=[dist_x]))
))
print(jdn.sample(10))

(我试图在第二个示例中明确地为分类建模,只是为了学习目的)

-- 更新:已解决 ---

显然,最后一个示例错误地使用了tf.gather_nd 而不是tf.gather,因为我们只想根据dist_x outome 选择第一行或第二行。这段代码现在可以工作了:

jdn = tfd.JointDistributionNamed(dict(
    dist_x=tfd.Categorical([0.2, 0.8], validate_args=True),
    dist_y=lambda dist_x: tfd.Categorical(probs=tf.gather([[0.1, 0.9], [0.5, 0.5]], indices=[dist_x]))
))
print(jdn.sample(10))

【问题讨论】:

    标签: probability-distribution tensorflow-probability


    【解决方案1】:

    这方面的棘手之处,大概也是它在 PyMC 中比预期更微妙的原因 - 与矢量化编程中的几乎所有东西一样 - 处理形状。

    在 TF/TFP 中,(IMO) 解决此问题的最佳方法是使用新的 TFP JointDistribution{Sequential,Named,Coroutine} 类之一。这些让您可以自然地表示分层 PGM 模型,然后从中采样、评估日志概率等。

    我为整个学生网络制作了一个演示所有 3 种方法的 colab 笔记本:https://colab.research.google.com/drive/1D2VZ3OE6tp5pHTsnOAf_7nZZZ74GTeex

    注意 tf.gather 和 tf.gather_nd 在管理各种二进制和分类切换的矢量化方面的关键用途。

    看看,如果您有任何问题,请告诉我!

    【讨论】:

    • 非常感谢克里斯的详尽回答!因此,一般来说,要点是可以使用将另一个分布作为参数的函数对分布进行参数化。诀窍是将矢量化操作与 tf.gather 一起使用。对我来说仍然有点不清楚,但绝对是深入挖掘以理解它的一个很好的起点,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-12
    • 2012-12-17
    • 2012-07-23
    相关资源
    最近更新 更多