我的最终目标是模拟似然比测试统计数据,但是,我遇到的核心问题是我不明白如何让 TensorFlow 2 为不同的数据输入执行许多优化。这是我的尝试,希望它能让您了解我正在尝试的内容:
import tensorflow as tf
import tensorflow_probability as tfp
from tensorflow_probability import distributions as tfd
import numpy as np
# Bunch of independent Poisson distributions that we want to combine
poises0 = [tfp.distributions.Poisson(rate = 10) for i in range(5)]
# Construct joint distributions
joint0 = tfd.JointDistributionSequential(poises0)
# Generate samples
N = int(1e3)
samples0 = joint0.sample(N)
# Now we need the same distributions but with floating parameters,
# and need to define the function to be minimised
mus = [tf.Variable(np.random.randn(), name='mu{0}'.format(i)) for i in range(5)]
#@tf.function
def loss():
poises_free = [tfp.distributions.Poisson(rate = mus[i]) for i in range(5)]
joint_free = tfd.JointDistributionSequential(poises_free)
# Construct (half of) test statistic
return -2*(joint_free.log_prob(samples0))
# Minimise (for all samples? Apparently not?)
opt = tf.optimizers.SGD(0.1).minimize(loss,var_list=mus)
print(mus)
print(loss())
print(opt)
quit()
输出:
[<tf.Variable 'mu0:0' shape=() dtype=float32, numpy=53387.016>, <tf.Variable 'mu1:0' shape=() dtype=float32, numpy=2540.568>, <tf.Variable 'mu2:0' shape=() dtype=float32, numpy=-5136.6226>, <tf.Variable 'mu3:0' shape=() dtype=float32, numpy=-3714.5227>, <tf.Variable 'mu4:0' shape=() dtype=float32, numpy=1062.9396>]
tf.Tensor(
[nan nan nan nan ... nan nan nan], shape=(1000,), dtype=float32)
<tf.Variable 'UnreadVariable' shape=() dtype=int64, numpy=1>
最后我想计算测试统计
q = -2*joint0.log_prob(samples0) - loss()
并表明它具有 5 个自由度的卡方分布。
我是 TensorFlow 的新手,所以也许我这样做完全错误,但我希望你能明白我想要什么。
编辑:
所以我玩了更多,我想 TensorFlow 根本不会像我假设的那样对输入张量进行并行优化。或者也许可以,但我需要进行不同的设置,即也许给它一个输入参数的张量和一个巨大的联合损失函数来一次所有的最小化?
我也尝试用一个简单的循环来做事,看看会发生什么。正如预测的那样,它慢得可怜,但我什至没有得到正确的答案:
poises0 = [tfp.distributions.Poisson(rate = 10) for i in range(5)]
joint0 = tfd.JointDistributionSequential(poises0)
N = int(5e2)
samples0 = joint0.sample(N)
mus = [tf.Variable(10., name='mu{0}'.format(i)) for i in range(5)]
#@tf.function
def loss(xi):
def loss_inner():
poises_free = [tfp.distributions.Poisson(rate = mus[i]) for i in range(5)]
joint_free = tfd.JointDistributionSequential(poises_free)
# Construct (half of) test statistic
return -2*(joint_free.log_prob(xi))
return loss_inner
# Minimise
# I think I have to loop over the samples... bit lame. Can perhaps parallelise though.
q = []
for i in range(N):
xi = [x[i] for x in samples0]
opt = tf.optimizers.SGD(0.1).minimize(loss=loss(xi),var_list=mus)
q += [-2*joint0.log_prob(xi) - loss(xi)()]
fig = plt.figure()
ax = fig.add_subplot(111)
sns.distplot(q, kde=False, ax=ax, norm_hist=True)
qx = np.linspace(np.min(q),np.max(q),1000)
qy = np.exp(tfd.Chi2(df=5).log_prob(qx))
sns.lineplot(qx,qy)
plt.show()
输出不是 DOF=5 的卡方分布。实际上,检验统计量通常具有负值,这意味着优化后的结果通常比零假设更差,这应该是不可能的。
编辑2:
这是对“怪物”解决方案的一次尝试,我一次将每个伪数据实现的不同输入变量的巨大网络最小化。这感觉更像是 TensorFlow 可能擅长做的事情,尽管我觉得一旦我处理大量伪数据集就会耗尽内存。不过,我可能可以遍历成批的伪数据。
poises0 = [tfp.distributions.Poisson(rate = 10) for i in range(5)]
joint0 = tfd.JointDistributionSequential(poises0)
N = int(5e3)
samples0 = joint0.sample(N)
mus = [tf.Variable(10*np.ones(N, dtype='float32'), name='mu{0}'.format(i)) for i in range(5)]
poises_free = [tfp.distributions.Poisson(rate = mus[i]) for i in range(5)]
joint_free = tfd.JointDistributionSequential(poises_free)
qM = -2*(joint_free.log_prob(samples0))
@tf.function
def loss():
return tf.math.reduce_sum(qM,axis=0)
# Minimise
opt = tf.optimizers.SGD(0.1).minimize(loss,var_list=mus)
print("parameters:", mus)
print("loss:", loss())
q0 =-2*joint0.log_prob(samples0)
print("q0:", q0)
print("qM:", qM)
q = q0 - qM
fig = plt.figure()
ax = fig.add_subplot(111)
sns.distplot(q, kde=False, ax=ax, norm_hist=True)
qx = np.linspace(np.min(q),np.max(q),1000)
qy = np.exp(tfd.Chi2(df=5).log_prob(qx))
sns.lineplot(qx,qy)
plt.show()
不幸的是,我现在收到错误:
Traceback (most recent call last):
File "testing3.py", line 35, in <module>
opt = tf.optimizers.SGD(0.1).minimize(loss,var_list=mus)
File "/home/farmer/anaconda3/envs/general/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py", line 298, in minimize
return self.apply_gradients(grads_and_vars, name=name)
File "/home/farmer/anaconda3/envs/general/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py", line 396, in apply_gradients
grads_and_vars = _filter_grads(grads_and_vars)
File "/home/farmer/anaconda3/envs/general/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py", line 924, in _filter_grads
([v.name for _, v in grads_and_vars],))
ValueError: No gradients provided for any variable: ['mu0:0', 'mu1:0', 'mu2:0', 'mu3:0', 'mu4:0'].
我认为这是一种基本的错误。我想我只是不明白 TensorFlow 如何跟踪它需要计算的导数。如果我在损失函数内部而不是外部定义变量,似乎一切正常,但我需要在外部使用它们以便稍后访问它们的值。所以我想我不明白这里的一些东西。