SheffieldML / GPy

Gaussian processes framework in python
BSD 3-Clause "New" or "Revised" License
2.01k stars 557 forks source link

Can't instantiate priors #503

Open aplavin opened 7 years ago

aplavin commented 7 years ago

Many priors from 'GPy.priors' don't work at all:

In [2]: GPy.priors.Uniform()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-157dba2fded5> in <module>()
----> 1 GPy.priors.Uniform()

/home/aplavin/anaconda3/lib/python3.6/site-packages/GPy/core/parameterization/priors.py in __new__(cls, lower, upper)
    102                 if instance().lower == lower and instance().upper == upper:
    103                     return instance()
--> 104         o = super(Prior, cls).__new__(cls, lower, upper)
    105         cls._instances.append(weakref.ref(o))
    106         return cls._instances[-1]()

TypeError: object() takes no parameters
In [3]: GPy.priors.Uniform(0, 1)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-33389462e27b> in <module>()
----> 1 GPy.priors.Uniform(0, 1)

/home/aplavin/anaconda3/lib/python3.6/site-packages/GPy/core/parameterization/priors.py in __new__(cls, lower, upper)
    102                 if instance().lower == lower and instance().upper == upper:
    103                     return instance()
--> 104         o = super(Prior, cls).__new__(cls, lower, upper)
    105         cls._instances.append(weakref.ref(o))
    106         return cls._instances[-1]()

TypeError: object() takes no parameters

same issue with Exponential. On the other hand, some priors do work:

In [5]: GPy.priors.Gamma(1, 2)
Out[5]: Ga(1, 2)

but only with explicitly specified parameters, otherwise:

In [3]: GPy.priors.Uniform(0, 1)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-33389462e27b> in <module>()
----> 1 GPy.priors.Uniform(0, 1)

/home/aplavin/anaconda3/lib/python3.6/site-packages/GPy/core/parameterization/priors.py in __new__(cls, lower, upper)
    102                 if instance().lower == lower and instance().upper == upper:
    103                     return instance()
--> 104         o = super(Prior, cls).__new__(cls, lower, upper)
    105         cls._instances.append(weakref.ref(o))
    106         return cls._instances[-1]()

TypeError: object() takes no parameters
michalisfrangos commented 7 years ago

Just commenting to mention I have tried your examples and I confirm the issue

For uniform, perhaps you can set a bound instead?

model.kern.variance.constrain_bounded(1,2)

OwenThomas commented 6 years ago

Hello,

Another bump for this issue, I am also experiencing it.

ermeel86 commented 5 years ago

Same problem here with version 1.9.8 and InvGamma. Gamma works with two parameters but not InvGamma.

JasperKirton commented 4 years ago

HalfT doesn't work either... Anyone have trouble with Gamma fitting non-modal values under the log prior? seems to be out by a factor of 3 or so

isaacmasher commented 4 years ago

I got this issue as well (just upgraded to Python 3.8). Seems to be due to an issue in the __new__ method. InverseGamma has this (in GPy/core/parameterization/priors.py) and fails:

o = super(Prior, cls).__new__(cls, a, b)

Whereas Gamma has this and works:

newfunc = super(Prior, cls).__new__
if newfunc is object.__new__:
    o = newfunc(cls)  
else:
    o = newfunc(cls, a, b)

By swapping out I got InverseGamma to work. Probably similar for other priors.

yeahyelina commented 2 years ago

Did anyone solve this problem? I have the exactly same issue. I tried the above one, but it fixed nothing.

daniel-spies commented 5 months ago

I got this issue as well (just upgraded to Python 3.8). Seems to be due to an issue in the __new__ method. InverseGamma has this (in GPy/core/parameterization/priors.py) and fails:

o = super(Prior, cls).__new__(cls, a, b)

Whereas Gamma has this and works:

newfunc = super(Prior, cls).__new__
if newfunc is object.__new__:
    o = newfunc(cls)  
else:
    o = newfunc(cls, a, b)

By swapping out I got InverseGamma to work. Probably similar for other priors.

this got it running for me though as it's called from another package (DP_GP) that is re-setting priors on each update with the shape and rate parameter I'm not sure if this is doing exactly what it' supposed to, so I also added the property blocks that are present in the Gamma class which seem to have been updated to handle this type of error:

class InverseGamma(Gamma):
    """
    Implementation of the inverse-Gamma probability function, coupled with random variables.

    :param a: shape parameter
    :param b: rate parameter (warning: it's the *inverse* of the scale)

    .. Note:: Bishop 2006 notation is used throughout the code
    """
    domain = _POSITIVE
    _instances = []
    def __new__(cls, a=1, b=.5): # Singleton:
        if cls._instances:
            cls._instances[:] = [instance for instance in cls._instances if instance()]
            for instance in cls._instances:
                if instance().a == a and instance().b == b:
                    return instance()
        newfunc = super(Prior, cls).__new__
        if newfunc is object.__new__:
            o = newfunc(cls)
        else:
            o = newfunc(cls, a, b)
        #o = super(Prior, cls).__new__(cls, a, b)
        cls._instances.append(weakref.ref(o))
        return cls._instances[-1]()

    @property
    def a(self):
        return self._a

    @property
    def b(self):
        return self._b

    def __init__(self, a, b):
        self._a = float(a)
        self._b = float(b)
        self.constant = -gammaln(self.a) + a * np.log(b)

    def __str__(self):
        return "iGa({:.2g}, {:.2g})".format(self.a, self.b)

    def lnpdf(self, x):
        return self.constant - (self.a + 1) * np.log(x) - self.b / x

    def lnpdf_grad(self, x):
        return -(self.a + 1.) / x + self.b / x ** 2

    def rvs(self, n):
        return 1. / np.random.gamma(scale=1. / self.b, shape=self.a, size=n)