我试图使用pymc3定义复杂的自定义似然函数。似然函数涉及大量迭代,因此我尝试使用theano的扫描方法直接在theano中定义迭代。这是一个极其简化的例子,说明了我面临的挑战。我试图定义的(假的)似然函数只是两个pymc3随机变量p和theta的总和。当然,我可以简单地返回p + theta,但我尝试编写的实际似然函数更复杂,我相信我需要使用theano.scan,因为它涉及大量的迭代。
import pymc3 as pm
from pymc3 import Model, Uniform, DensityDist
import theano.tensor as T
import theano
import numpy as np
### theano test
theano.config.compute_test_value = 'raise'
X = np.asarray([[1.0,2.0,3.0],[1.0,2.0,3.0]])
### pymc3 implementation
with Model() as bg_model:
p = pm.Uniform('p', lower = 0, upper = 1)
theta = pm.Uniform('theta', lower = 0, upper = .2)
def logp(X):
f = p+theta
print("f",f)
get_ll = theano.function(name='get_ll',inputs = [p, theta], outputs = f)
print("p keys ",p.__dict__.keys())
print("theta keys ",theta.__dict__.keys())
print("p name ",p.name,"p.type ",p.type,"type(p)",type(p),"p.tag",p.tag)
result=get_ll(p, theta)
print("result",result)
return result
y = pm.DensityDist('y', logp, observed = X) # Nx4 y = f(f,x,tx,n | p, theta)
当我运行时,我收到错误:
TypeError: ('Bad input argument to theano function with name "get_ll" at index 0(0-based)', 'Expected an array-like object, but found a Variable: maybe you are trying to call a function on a (possibly shared) variable instead of a numeric array?')
我知道这个问题符合要求 result = get_ll(p,theta)
因为p和theta属于pymc3.TransformedRV类型,并且theano函数的输入需要是简单numpy数组的标量数。然而,pymc3 TransformedRV似乎没有任何明显的方法来获得随机变量本身的当前值。
是否可以定义一个对数似然函数,该函数涉及使用aano函数作为pymc3随机变量的输入?
答案 0 :(得分:1)
问题是你的th.function get_ll是一个编译的theano函数,它作为输入数值数组。相反,pymc3正在向它发送一个符号变量(theano tensor)。这就是您收到错误的原因。
关于你的解决方案,你说得对,只是回归p + theta就是你要走的路。如果你的logp中有扫描和诸如此类的东西,那么你将返回感兴趣的扫描变量;这里没有必要编译theano函数。例如,如果你想为向量的每个元素添加1(作为一个不切实际的玩具示例),你会这样做:
def logp(X):
the_sum, the_sum_upd = th.scan(lambda x: x+1, sequences=[X])
return the_sum
话虽这么说,如果你需要渐变,你需要在theano Op中计算你的the_sum变量并提供一个grad()方法(你可以在答案上看到一个玩具示例{{3} })。如果你不需要渐变,你最好不要在python(或C,numba,cython,性能)和使用as_op装饰器中做所有事情。