I'm trying to define a complex custom likelihood function using pymc3. The likelihood function involves a lot of iteration, and therefore I'm trying to use theano's scan method to define iteration directly within theano. Here's a greatly simplified example that illustrates the challenge that I'm facing. The (fake) likelihood function I'm trying to define is simply the sum of two pymc3 random variables, p and theta. Of course, I could simply return p+theta, but the actual likelihood function I'm trying to write is more complicated, and I believe I need to use theano.scan since it involves a lot of iteration.
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)
When I run this, I get the error:
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?')
I understand that the issue occurs in line
result=get_ll(p, theta)
because p and theta are of type pymc3.TransformedRV, and that the input to a theano function needs to be a scalar number of a simple numpy array. However, a pymc3 TransformedRV does not seem to have any obvious way of obtaining the current value of the random variable itself.
Is it possible to define a log likelihood function that involves the use of a theano function that takes as input a pymc3 random variable?
The problem is that your th.function get_ll is a compiled theano function, which takes as input numerical arrays. Instead, pymc3 is sending it a symbolic variable (theano tensor). That's why you're getting the error.
As to your solution, you're right in saying that just returning p+theta is the way to go. If you have scans and whatnot in your logp, then you would return the scan variable of interest; there is no need to compile a theano function here. For example, if you wanted to add 1 to each element of a vector (as an impractical toy example), you would do:
def logp(X):
the_sum, the_sum_upd = th.scan(lambda x: x+1, sequences=[X])
return the_sum
That being said, if you need gradients, you would need to calculate your the_sum variable in a theano Op and provide a grad() method along with it (you can see a toy example of that on the answer here). If you do not need gradients, you might be better off doing everything in python (or C, numba, cython, for performance) and using the as_op decorator.
Related
While using integrate in the scipy module, I notice that the values of the integral do not match with the expected value (which I computed by hand).
I have a simple function as follows:
import math
def integrand(x, L):
return (math.cos(sc.pi * x / L))**2
L=10
I = quad(integrand, 0, 1, args=(L))
I = 0.9677446418943196 # from scipy
But theoretically, the result should be 0.5519233944327677. I am quite confused as to why discrepancy exists.
The integral I am trying to find is as follows:
The scipy is correct. Your calculation is incorrect:
Note that the Decimal given matches the one obtained by scipy. This question is best suited for stackexchange.
I am to maximize my non-linear function and trying to do that with GEKKO
m=GEKKO()
x=m.Var(value=1,lb=0, ub=50)
y=m.Var(value=1, lb=0, ub=50)
m.Equation(puree*x+cutlet*y==1500)
m.Obj(-min(x,y))
m.solve(disp=False)
x.value
y.value
but I get TypeError: object of type 'int' has no len() in this string m.Obj(-min(x,y)) and I don't know what to change to make it work...
Your x and y are specific Gekko variable types, even though when you display them they display as integers. There is no min function defined on that specific type. So when you call min, the Python builtin min function depends on len, and the Gekko specific len function takes as its argument the value of the variable, so effectively min calls len(x.value), which does not work because x.value is an int (equivalently for y). If you want to set your objective function to be some function of x and y, then you need to do it as such:
m.Obj(<f(x,y)>)
and Gekko will try to minimize f. So if you just want to minimize x+y, then all you need is m.Obj(x+y).
As tclarke13 correctly points out, you need to use the m.min2() or m.min3() functions to create a continuously differentiable version of the minimum function.
from gekko import GEKKO
m=GEKKO()
x,y = m.Array(m.Var,2,value=1,lb=0,ub=50)
puree=100; cutlet=120
m.Equation(puree*x+cutlet*y==1500)
m.Maximize(m.min3(x,y))
m.solve(disp=False)
print(x.value[0],y.value[0])
The m.min2() function uses complementarity constraints while the m.min3() function uses a binary variable. The binary variable requires that this problem is solved with either a Mixed Integer Linear Programming (MILP) solver or Mixed Integer Nonlinear Programming (MINLP) solver. Gekko automatically selects m.options.SOLVER=1 when you use m.min3(). This produces the solution:
6.8181818182
6.8181818182
More information on m.min2() is available here.
I am trying to create a Fibonacci number with high n by using matrix exponential but it gives me negative result. I have tried to change the integer objects but failed.
import numpy as np
def matrixmul(a,n):
a=np.array([[1,1],[1,0]])
return ((np.array([1,1],[1,0], dtype=np.object))**n)
matrixMul(a,100)
my output is
array([[-1869596475, -980107325],
[ -980107325, -889489150]])
but it was wrong. there should not be any negative number.
It's hard to answer on your question. Your code have some bugs:
You haven't initialize a
Also name of defined function is different than used (python is case-sensitive)
Then in function you are not using a (because it is not in return)
And most important thing is that you can not use **n too get exponential of matrix. Instead you can try to find right function in scipy library. Probably expm() function can be right for this perpuse.
I've been trying to implement a custom objective function in Keras (the negative log likelihood of the normal distribution)
Keras expects one argument for the ground truth tensor, and one for the predictions tensor; for y_pred,I'm passing a tensor that should represent a nx2 matrix where the first column is the mean of the distribution, and the second the precision.
My problem is that I haven't been able to get a clear idea how I properly slice y_pred before passing it into the likelihood function without yielding the error
'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?'
While I understand that I'm feeding l_func arguments of the variable type when it expects an array,I don't seem to be able to grok how to properly split the input y_pred variable into its mean and precision components to plug into the likelihood function. Here are some attempts; if someone could enlighten me about how to proceed, I would greatly appreciate it.
def log_likelihood(y_true,y_pred):
mu = T.vector('mu')
beta = T.vector('beta')
x=T.vector('x')
likelihood = .5*(beta*(x-mu)**2)-T.log(beta/(2*np.pi))
l_func = function([mu,beta,x], likelihood)
return(l_func(y_pred[:,0],y_pred[:,1],y_true))
def log_likelihood(y_true,y_pred):
likelihood = .5*(y_pred[:,1]*(y_true-y_pred[:,0])**2)-T.log(y_pred[:,1]/(2*np.pi))
l_func = function([y_true,y_pred], likelihood)
return(l_func(y_true,y_pred))
def log_likelihood(y_true,y_pred):
mu=y_pred[:,0]
beta=y_pred[:,1]
x=y_true
mu_function=function([y_pred],mu)
beta_function=function([y_pred],beta)
id_function=function([y_true],x)
likelihood = .5*(beta_function(y_pred)*(id_function(y_true)-mu_function(y_pred))**2)-T.log(beta_function(y_pred)/(2*np.pi))
l_func = function([y_true,y_pred], likelihood)
return(l_func(y_true,y_pred))
If I have a cost that is the imaginary part of a complex number, trying to obtain the gradient with theano I get the following error:
TypeError: Elemwise{imag,no_inplace}.grad illegally returned an integer-valued variable. (Input index 0, dtype complex128)
Is it not possible to use the imaginary part as cost despite it being a real-valued cost?
Edit. Minimal working example
import theano.tensor as T
from theano import function
a = T.zscalar('a')
f = function([a], T.grad(T.imag(a),a))
I would expect this to work as T.imag(a) is a real scalar cost..