python - 将张量流概率分布作为双射器参数传递
问题描述
我想创建一个 TransformedDistribution ,其变换双射器(双射器链)的一些组件参数化为分布本身,目的是每次通过双射器转换一些张量时都有不同的结果(因为双射器的参数将是每次也采样)。
让我们举一个非常简单的例子来说明我所说的(没有链):
import tensorflow as tf
import tensorflow_probability as tfp
tfd = tfp.distributions
tfb = tfp.bijectors
base_distribution = tfd.Normal(loc=0, scale=1.5)
x = base_distribution.sample(10) # Sample 10 times, to get fixed values
# Define the distribution for the parameter of the bijector
scale_distribution = tfd.Uniform(low=2/3-0.5, high=2/3+0.5)
# This is how I wish it was, but fails
bijector = tfb.Scale(scale=scale_distribution)
# ValueError: TypeError: object of type 'Uniform' has no len()
详细说明这个例子:
transformed_dist = tfd.TransformedDistribution(
base_distribution,
bijector)
transformed_dist.sample() # get one sample of the original distribution,
# scaled with some scale factor drawn from the
# uniform distribution.
我知道有一种方法可以使用 JointDistribution 构建分层分布模型,这让我可以使用一个(或多个)分布作为另一个分布的参数,然后从联合分布中采样。
但我还没有找到随机参数化双射器的等效方法。一种“有效”但有点麻烦的方法是:
# Works, but the sample is generated and becomes fixed when defining the bijector
bijector = tfb.Scale(scale=tf.random.uniform(minval=2/3-0.5, maxval=2/3+0.5,))
transformed_dist = tfd.TransformedDistribution(
base_distribution,
bijector)
transformed_dist.sample() # Now the distribution will always sample from
# a Normal what is Scaled by a deterministic
# parameter, that was randomly generated at
# definition time.
正如我在代码中解释的那样,每次我希望参数不同时,我都需要重新运行整个代码块。
我想这样做的原因是我想以这样一种方式自动生成样本,即某个旋转是随机的,即每次采样时得到不同的分布。
注意:我正在使用 tensorflow >2.1 和急切的执行。
解决方案
我仍然认为 JointDistribution 是去这里的方式,做类似的事情
joint = tfd.JointDistributionSequential([
tfd.Uniform(...),
lambda unif: tfb.MyBijector(param=unif)(tfd.Normal(0., 1.))
])
输入双射器参数。
但是,您也可以将某些东西与tfp.util.DeferredTensor
. 这是一个可以在任何地方使用张量的对象,但其值取自给定函数的执行。例如
rand_dt = tfp.util.DeferredTensor(
pretransformed_input=1., # value doesn't matter here
transform_fn=lambda _: tf.random.uniform(minval=1., maxval=2.)
)
td = tfb.Scale(scale=rand_dt)(tfd.Normal(0., 1.))
for i in range(5):
print(td.sample())
# will print a sample with a different random scale on each call
这是一个 colab,对上述示例进行了略微修改,以说明正在发生的事情:https ://colab.research.google.com/drive/1akjX6a1W-RJoUjsy0hVOrrRAQiBIYjY-
!
更新:
经过进一步思考,我实际上应该对第二种模式非常谨慎。不幸的是,很难保证 DeferredTensor 的单个张量化值将被一致地使用——即使在单个 Distribution 方法调用的上下文中——所以做任何有副作用的事情都可能是危险的。例如:
rand_dt = tfp.util.DeferredTensor(
pretransformed_input=1., # value doesn't matter here
transform_fn=lambda _: tf.random.uniform(minval=1., maxval=2.)
)
td = tfb.Scale(scale=rand_dt)(tfd.Normal(0., 1.))
sample = td.sample() # sample from TD with some random scale
print(td.log_prob(sample)) # new scale; wrong log_prob!
一种解决方法是使用无状态 TF 采样 API,直接或通过将列表值或张量值种子传递给 TFP(在此处查看有关无状态采样语义的更多信息),并显式管理种子。不过,这可能会使上面的示例变得更加丑陋且难以使用(您可能需要有一个浮动的变量作为种子输入,并且assign
每次需要新样本时都会被编辑)
您最好的选择可能是使用 JointDistribution 方法!
推荐阅读
- vbscript - 如何为用户“隐藏”或“重命名”页面名称/位置/url,但仍允许外部站点通过 HTTP_REFERER 正确读取真实 url
- .net-core - 当我在中间件中覆盖响应正文时,为什么没有调整响应正文的大小?
- javascript - 角色分配机器人有时不会删除角色
- ssl - 为什么连续数据包中相同数据的 TLS 对称加密不同?
- knex.js - 带有 Sqlite 的 Knex 是否需要销毁才能运行多个查询?
- blazor - 检测授权何时完成
- r - 如何在交互图中的各个方面注释文本(`ggplot2`;`interactions`)?
- redirect - 将网站从 www 和非 www 重定向到 https
- javascript - 我如何检查一个数组是否有 2 个或更多相同的值,如果有则返回 false?
- javascript - 节点重定向到重复 URL