mirror of
https://github.com/SheffieldML/GPy.git
synced 2026-06-26 15:49:40 +02:00
Merge branch 'devel' of https://github.com/SheffieldML/GPy into wgps_improvements
Merging new devel
This commit is contained in:
commit
76f3ff65a1
45 changed files with 729 additions and 378 deletions
34
.travis.yml
34
.travis.yml
|
|
@ -20,33 +20,17 @@ env:
|
||||||
- PYTHON_VERSION=3.5
|
- PYTHON_VERSION=3.5
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- export CONDA_CACHED=1
|
- wget https://github.com/mzwiessele/travis_scripts/raw/master/download_miniconda.sh
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]];
|
- wget https://github.com/mzwiessele/travis_scripts/raw/master/install_retry.sh
|
||||||
then export OS=Linux;
|
- source download_miniconda.sh
|
||||||
elif [[ "$TRAVIS_OS_NAME" == "osx" ]];
|
- echo $PATH
|
||||||
then export OS=MacOSX;
|
|
||||||
brew install pandoc;
|
|
||||||
else
|
|
||||||
echo "OS not supported yet";
|
|
||||||
exit 1; fi;
|
|
||||||
- if [[ $PYTHON_VERSION == "2.7" ]];
|
|
||||||
then export MINICONDA=Miniconda;
|
|
||||||
elif [[ $PYTHON_VERSION == 3* ]];
|
|
||||||
then export MINICONDA=Miniconda3;
|
|
||||||
else echo "Could not find python version";exit 1; fi;
|
|
||||||
- if [ ! -d $HOME/download/ ]; then mkdir $HOME/download/; fi;
|
|
||||||
- if [ ! -d $HOME/install/ ]; then mkdir $HOME/install/; fi;
|
|
||||||
- export MINICONDA_FILE=$MINICONDA-latest-$OS-x86_64-$PYTHON_VERSION
|
|
||||||
- export MINCONDA_CACHE_FILE=$HOME/download/$MINICONDA_FILE.sh
|
|
||||||
- export MINICONDA_INSTALL=$HOME/install/$MINICONDA_FILE
|
|
||||||
- if [ ! -f $MINCONDA_CACHE_FILE ]; then export CONDA_CACHED=0; wget http://repo.continuum.io/miniconda/$MINICONDA-latest-$OS-x86_64.sh -O $MINCONDA_CACHE_FILE; bash $MINCONDA_CACHE_FILE -b -p $MINICONDA_INSTALL; fi;
|
|
||||||
- export PATH="$MINICONDA_INSTALL/bin:$PATH";
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- conda install --yes python=$PYTHON_VERSION numpy=1.9 scipy=0.16 nose pip six matplotlib sphinx;
|
- echo $PATH
|
||||||
- pip install codecov
|
- source install_retry.sh
|
||||||
- pip install pypandoc
|
- pip install codecov
|
||||||
- python setup.py develop
|
- pip install pypandoc
|
||||||
|
- python setup.py develop
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- coverage run travis_tests.py
|
- coverage run travis_tests.py
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
__version__ = "0.9.4"
|
__version__ = "0.9.7"
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@ class GP(Model):
|
||||||
def parameters_changed(self):
|
def parameters_changed(self):
|
||||||
"""
|
"""
|
||||||
Method that is called upon any changes to :class:`~GPy.core.parameterization.param.Param` variables within the model.
|
Method that is called upon any changes to :class:`~GPy.core.parameterization.param.Param` variables within the model.
|
||||||
In particular in the GP class this method reperforms inference, recalculating the posterior and log marginal likelihood and gradients of the model
|
In particular in the GP class this method re-performs inference, recalculating the posterior and log marginal likelihood and gradients of the model
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
This method is not designed to be called manually, the framework is set up to automatically call this method upon changes to parameters, if you call
|
This method is not designed to be called manually, the framework is set up to automatically call this method upon changes to parameters, if you call
|
||||||
|
|
@ -365,13 +365,14 @@ class GP(Model):
|
||||||
mean_jac[:,:,i] = kern.gradients_X(self.posterior.woodbury_vector[:,i:i+1].T, Xnew, self._predictive_variable)
|
mean_jac[:,:,i] = kern.gradients_X(self.posterior.woodbury_vector[:,i:i+1].T, Xnew, self._predictive_variable)
|
||||||
|
|
||||||
dK_dXnew_full = np.empty((self._predictive_variable.shape[0], Xnew.shape[0], Xnew.shape[1]))
|
dK_dXnew_full = np.empty((self._predictive_variable.shape[0], Xnew.shape[0], Xnew.shape[1]))
|
||||||
|
one = np.ones((1,1))
|
||||||
for i in range(self._predictive_variable.shape[0]):
|
for i in range(self._predictive_variable.shape[0]):
|
||||||
dK_dXnew_full[i] = kern.gradients_X([[1.]], Xnew, self._predictive_variable[[i]])
|
dK_dXnew_full[i] = kern.gradients_X(one, Xnew, self._predictive_variable[[i]])
|
||||||
|
|
||||||
if full_cov:
|
if full_cov:
|
||||||
dK2_dXdX = kern.gradients_XX([[1.]], Xnew)
|
dK2_dXdX = kern.gradients_XX(one, Xnew)
|
||||||
else:
|
else:
|
||||||
dK2_dXdX = kern.gradients_XX_diag([[1.]], Xnew)
|
dK2_dXdX = kern.gradients_XX_diag(one, Xnew)
|
||||||
|
|
||||||
def compute_cov_inner(wi):
|
def compute_cov_inner(wi):
|
||||||
if full_cov:
|
if full_cov:
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ class SVGP(SparseGP):
|
||||||
"""
|
"""
|
||||||
Return a new batch of X and Y by taking a chunk of data from the complete X and Y
|
Return a new batch of X and Y by taking a chunk of data from the complete X and Y
|
||||||
"""
|
"""
|
||||||
i = self.slicer.next()
|
i = next(self.slicer)
|
||||||
return self.X_all[i], self.Y_all[i]
|
return self.X_all[i], self.Y_all[i]
|
||||||
|
|
||||||
def stochastic_grad(self, parameters):
|
def stochastic_grad(self, parameters):
|
||||||
|
|
|
||||||
|
|
@ -459,7 +459,7 @@ def mrd_simulation(optimize=True, verbose=True, plot=True, plot_sim=True, **kw):
|
||||||
D1, D2, D3, N, num_inducing, Q = 60, 20, 36, 60, 6, 5
|
D1, D2, D3, N, num_inducing, Q = 60, 20, 36, 60, 6, 5
|
||||||
_, _, Ylist = _simulate_sincos(D1, D2, D3, N, num_inducing, plot_sim)
|
_, _, Ylist = _simulate_sincos(D1, D2, D3, N, num_inducing, plot_sim)
|
||||||
|
|
||||||
k = kern.Linear(Q) + kern.White(Q, variance=1e-4)
|
k = kern.Linear(Q, ARD=True) + kern.White(Q, variance=1e-4)
|
||||||
m = MRD(Ylist, input_dim=Q, num_inducing=num_inducing, kernel=k, initx="PCA_concat", initz='permute', **kw)
|
m = MRD(Ylist, input_dim=Q, num_inducing=num_inducing, kernel=k, initx="PCA_concat", initz='permute', **kw)
|
||||||
|
|
||||||
m['.*noise'] = [Y.var() / 40. for Y in Ylist]
|
m['.*noise'] = [Y.var() / 40. for Y in Ylist]
|
||||||
|
|
@ -479,7 +479,7 @@ def mrd_simulation_missing_data(optimize=True, verbose=True, plot=True, plot_sim
|
||||||
D1, D2, D3, N, num_inducing, Q = 60, 20, 36, 60, 6, 5
|
D1, D2, D3, N, num_inducing, Q = 60, 20, 36, 60, 6, 5
|
||||||
_, _, Ylist = _simulate_matern(D1, D2, D3, N, num_inducing, plot_sim)
|
_, _, Ylist = _simulate_matern(D1, D2, D3, N, num_inducing, plot_sim)
|
||||||
|
|
||||||
k = kern.Linear(Q) + kern.White(Q, variance=1e-4)
|
k = kern.Linear(Q, ARD=True) + kern.White(Q, variance=1e-4)
|
||||||
inanlist = []
|
inanlist = []
|
||||||
|
|
||||||
for Y in Ylist:
|
for Y in Ylist:
|
||||||
|
|
|
||||||
|
|
@ -190,8 +190,8 @@ class VarDTC(LatentFunctionInference):
|
||||||
tmp, _ = dtrtrs(Lm, psi1V, lower=1, trans=0)
|
tmp, _ = dtrtrs(Lm, psi1V, lower=1, trans=0)
|
||||||
tmp, _ = dpotrs(LB, tmp, lower=1)
|
tmp, _ = dpotrs(LB, tmp, lower=1)
|
||||||
woodbury_vector, _ = dtrtrs(Lm, tmp, lower=1, trans=1)
|
woodbury_vector, _ = dtrtrs(Lm, tmp, lower=1, trans=1)
|
||||||
Bi, _ = dpotri(LB, lower=1)
|
#Bi, _ = dpotri(LB, lower=1)
|
||||||
symmetrify(Bi)
|
#symmetrify(Bi)
|
||||||
Bi = -dpotri(LB, lower=1)[0]
|
Bi = -dpotri(LB, lower=1)[0]
|
||||||
diag.add(Bi, 1)
|
diag.add(Bi, 1)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class VarDTC_minibatch(LatentFunctionInference):
|
||||||
self.limit = limit
|
self.limit = limit
|
||||||
|
|
||||||
# Cache functions
|
# Cache functions
|
||||||
from ...util.caching import Cacher
|
from paramz.caching import Cacher
|
||||||
self.get_trYYT = Cacher(self._get_trYYT, limit)
|
self.get_trYYT = Cacher(self._get_trYYT, limit)
|
||||||
self.get_YYTfactor = Cacher(self._get_YYTfactor, limit)
|
self.get_YYTfactor = Cacher(self._get_YYTfactor, limit)
|
||||||
|
|
||||||
|
|
@ -46,7 +46,7 @@ class VarDTC_minibatch(LatentFunctionInference):
|
||||||
self.mpi_comm = None
|
self.mpi_comm = None
|
||||||
self.midRes = {}
|
self.midRes = {}
|
||||||
self.batch_pos = 0
|
self.batch_pos = 0
|
||||||
from ...util.caching import Cacher
|
from paramz.caching import Cacher
|
||||||
self.get_trYYT = Cacher(self._get_trYYT, self.limit)
|
self.get_trYYT = Cacher(self._get_trYYT, self.limit)
|
||||||
self.get_YYTfactor = Cacher(self._get_YYTfactor, self.limit)
|
self.get_YYTfactor = Cacher(self._get_YYTfactor, self.limit)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,4 @@
|
||||||
|
|
||||||
|
|
||||||
# [plotting]
|
# [plotting]
|
||||||
# library = matplotlib # plotly
|
# library = matplotlib # plotly, none
|
||||||
|
|
|
||||||
|
|
@ -28,4 +28,4 @@ from .src.trunclinear import TruncLinear,TruncLinear_inf
|
||||||
from .src.splitKern import SplitKern,DEtime
|
from .src.splitKern import SplitKern,DEtime
|
||||||
from .src.splitKern import DEtime as DiffGenomeKern
|
from .src.splitKern import DEtime as DiffGenomeKern
|
||||||
from .src.spline import Spline
|
from .src.spline import Spline
|
||||||
from .src.basis_funcs import LinearSlopeBasisFuncKernel, BasisFuncKernel, ChangePointBasisFuncKernel, DomainKernel
|
from .src.basis_funcs import LogisticBasisFuncKernel, LinearSlopeBasisFuncKernel, BasisFuncKernel, ChangePointBasisFuncKernel, DomainKernel
|
||||||
|
|
@ -18,7 +18,7 @@ class ODE_UYC(Kern):
|
||||||
self.lengthscale_U = Param('lengthscale_U', lengthscale_U, Logexp())
|
self.lengthscale_U = Param('lengthscale_U', lengthscale_U, Logexp())
|
||||||
self.ubias = Param('ubias', ubias, Logexp())
|
self.ubias = Param('ubias', ubias, Logexp())
|
||||||
|
|
||||||
self.add_parameters(self.variance_Y, self.variance_U, self.lengthscale_Y, self.lengthscale_U, self.ubias)
|
self.link_parameters(self.variance_Y, self.variance_U, self.lengthscale_Y, self.lengthscale_U, self.ubias)
|
||||||
|
|
||||||
def K(self, X, X2=None):
|
def K(self, X, X2=None):
|
||||||
# model : a * dy/dt + b * y = U
|
# model : a * dy/dt + b * y = U
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ class ODE_st(Kern):
|
||||||
self.b = Param('b', b, Logexp())
|
self.b = Param('b', b, Logexp())
|
||||||
self.c = Param('c', c, Logexp())
|
self.c = Param('c', c, Logexp())
|
||||||
|
|
||||||
self.add_parameters(self.a, self.b, self.c, self.variance_Yt, self.variance_Yx, self.lengthscale_Yt,self.lengthscale_Yx)
|
self.link_parameters(self.a, self.b, self.c, self.variance_Yt, self.variance_Yx, self.lengthscale_Yt,self.lengthscale_Yx)
|
||||||
|
|
||||||
|
|
||||||
def K(self, X, X2=None):
|
def K(self, X, X2=None):
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class ODE_t(Kern):
|
||||||
self.a= Param('a', a, Logexp())
|
self.a= Param('a', a, Logexp())
|
||||||
self.c = Param('c', c, Logexp())
|
self.c = Param('c', c, Logexp())
|
||||||
self.ubias = Param('ubias', ubias, Logexp())
|
self.ubias = Param('ubias', ubias, Logexp())
|
||||||
self.add_parameters(self.a, self.c, self.variance_Yt, self.lengthscale_Yt,self.ubias)
|
self.link_parameters(self.a, self.c, self.variance_Yt, self.lengthscale_Yt,self.ubias)
|
||||||
|
|
||||||
def K(self, X, X2=None):
|
def K(self, X, X2=None):
|
||||||
"""Compute the covariance matrix between X and X2."""
|
"""Compute the covariance matrix between X and X2."""
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,8 @@ class Add(CombinationKernel):
|
||||||
return psi2
|
return psi2
|
||||||
|
|
||||||
def update_gradients_expectations(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior):
|
def update_gradients_expectations(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior):
|
||||||
|
tmp = dL_dpsi2.sum(0)+ dL_dpsi2.sum(1) if len(dL_dpsi2.shape)==2 else dL_dpsi2.sum(2)+ dL_dpsi2.sum(1)
|
||||||
|
|
||||||
if not self._exact_psicomp: return Kern.update_gradients_expectations(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior)
|
if not self._exact_psicomp: return Kern.update_gradients_expectations(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior)
|
||||||
from .static import White, Bias
|
from .static import White, Bias
|
||||||
for p1 in self.parts:
|
for p1 in self.parts:
|
||||||
|
|
@ -192,12 +194,13 @@ class Add(CombinationKernel):
|
||||||
if isinstance(p2, White):
|
if isinstance(p2, White):
|
||||||
continue
|
continue
|
||||||
elif isinstance(p2, Bias):
|
elif isinstance(p2, Bias):
|
||||||
eff_dL_dpsi1 += dL_dpsi2.sum(1) * p2.variance * 2.
|
eff_dL_dpsi1 += tmp * p2.variance
|
||||||
else:# np.setdiff1d(p1._all_dims_active, ar2, assume_unique): # TODO: Careful, not correct for overlapping _all_dims_active
|
else:# np.setdiff1d(p1._all_dims_active, ar2, assume_unique): # TODO: Careful, not correct for overlapping _all_dims_active
|
||||||
eff_dL_dpsi1 += dL_dpsi2.sum(1) * p2.psi1(Z, variational_posterior) * 2.
|
eff_dL_dpsi1 += tmp * p2.psi1(Z, variational_posterior)
|
||||||
p1.update_gradients_expectations(dL_dpsi0, eff_dL_dpsi1, dL_dpsi2, Z, variational_posterior)
|
p1.update_gradients_expectations(dL_dpsi0, eff_dL_dpsi1, dL_dpsi2, Z, variational_posterior)
|
||||||
|
|
||||||
def gradients_Z_expectations(self, dL_psi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior):
|
def gradients_Z_expectations(self, dL_psi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior):
|
||||||
|
tmp = dL_dpsi2.sum(0)+ dL_dpsi2.sum(1) if len(dL_dpsi2.shape)==2 else dL_dpsi2.sum(2)+ dL_dpsi2.sum(1)
|
||||||
if not self._exact_psicomp: return Kern.gradients_Z_expectations(self, dL_psi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior)
|
if not self._exact_psicomp: return Kern.gradients_Z_expectations(self, dL_psi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior)
|
||||||
from .static import White, Bias
|
from .static import White, Bias
|
||||||
target = np.zeros(Z.shape)
|
target = np.zeros(Z.shape)
|
||||||
|
|
@ -210,13 +213,15 @@ class Add(CombinationKernel):
|
||||||
if isinstance(p2, White):
|
if isinstance(p2, White):
|
||||||
continue
|
continue
|
||||||
elif isinstance(p2, Bias):
|
elif isinstance(p2, Bias):
|
||||||
eff_dL_dpsi1 += dL_dpsi2.sum(1) * p2.variance * 2.
|
eff_dL_dpsi1 += tmp * p2.variance
|
||||||
else:
|
else:
|
||||||
eff_dL_dpsi1 += dL_dpsi2.sum(1) * p2.psi1(Z, variational_posterior) * 2.
|
eff_dL_dpsi1 += tmp * p2.psi1(Z, variational_posterior)
|
||||||
target += p1.gradients_Z_expectations(dL_psi0, eff_dL_dpsi1, dL_dpsi2, Z, variational_posterior)
|
target += p1.gradients_Z_expectations(dL_psi0, eff_dL_dpsi1, dL_dpsi2, Z, variational_posterior)
|
||||||
return target
|
return target
|
||||||
|
|
||||||
def gradients_qX_expectations(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior):
|
def gradients_qX_expectations(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior):
|
||||||
|
tmp = dL_dpsi2.sum(0)+ dL_dpsi2.sum(1) if len(dL_dpsi2.shape)==2 else dL_dpsi2.sum(2)+ dL_dpsi2.sum(1)
|
||||||
|
|
||||||
if not self._exact_psicomp: return Kern.gradients_qX_expectations(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior)
|
if not self._exact_psicomp: return Kern.gradients_qX_expectations(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior)
|
||||||
from .static import White, Bias
|
from .static import White, Bias
|
||||||
target_grads = [np.zeros(v.shape) for v in variational_posterior.parameters]
|
target_grads = [np.zeros(v.shape) for v in variational_posterior.parameters]
|
||||||
|
|
@ -229,9 +234,9 @@ class Add(CombinationKernel):
|
||||||
if isinstance(p2, White):
|
if isinstance(p2, White):
|
||||||
continue
|
continue
|
||||||
elif isinstance(p2, Bias):
|
elif isinstance(p2, Bias):
|
||||||
eff_dL_dpsi1 += dL_dpsi2.sum(1) * p2.variance * 2.
|
eff_dL_dpsi1 += tmp * p2.variance
|
||||||
else:
|
else:
|
||||||
eff_dL_dpsi1 += dL_dpsi2.sum(1) * p2.psi1(Z, variational_posterior) * 2.
|
eff_dL_dpsi1 += tmp * p2.psi1(Z, variational_posterior)
|
||||||
grads = p1.gradients_qX_expectations(dL_dpsi0, eff_dL_dpsi1, dL_dpsi2, Z, variational_posterior)
|
grads = p1.gradients_qX_expectations(dL_dpsi0, eff_dL_dpsi1, dL_dpsi2, Z, variational_posterior)
|
||||||
[np.add(target_grads[i],grads[i],target_grads[i]) for i in range(len(grads))]
|
[np.add(target_grads[i],grads[i],target_grads[i]) for i in range(len(grads))]
|
||||||
return target_grads
|
return target_grads
|
||||||
|
|
|
||||||
|
|
@ -61,12 +61,12 @@ class Kern(Parameterized):
|
||||||
self.psicomp = PSICOMP_GH()
|
self.psicomp = PSICOMP_GH()
|
||||||
|
|
||||||
def __setstate__(self, state):
|
def __setstate__(self, state):
|
||||||
self._all_dims_active = range(0, max(state['active_dims'])+1)
|
self._all_dims_active = np.arange(0, max(state['active_dims'])+1)
|
||||||
super(Kern, self).__setstate__(state)
|
super(Kern, self).__setstate__(state)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _effective_input_dim(self):
|
def _effective_input_dim(self):
|
||||||
return self._all_dims_active.size
|
return np.size(self._all_dims_active)
|
||||||
|
|
||||||
@Cache_this(limit=20)
|
@Cache_this(limit=20)
|
||||||
def _slice_X(self, X):
|
def _slice_X(self, X):
|
||||||
|
|
|
||||||
|
|
@ -73,14 +73,15 @@ class Linear(Kern):
|
||||||
return np.sum(self.variances * np.square(X), -1)
|
return np.sum(self.variances * np.square(X), -1)
|
||||||
|
|
||||||
def update_gradients_full(self, dL_dK, X, X2=None):
|
def update_gradients_full(self, dL_dK, X, X2=None):
|
||||||
|
if X2 is None: dL_dK = (dL_dK+dL_dK.T)/2
|
||||||
if self.ARD:
|
if self.ARD:
|
||||||
if X2 is None:
|
if X2 is None:
|
||||||
#self.variances.gradient = np.array([np.sum(dL_dK * tdot(X[:, i:i + 1])) for i in range(self.input_dim)])
|
#self.variances.gradient = np.array([np.sum(dL_dK * tdot(X[:, i:i + 1])) for i in range(self.input_dim)])
|
||||||
self.variances.gradient = np.einsum('ij,iq,jq->q', dL_dK, X, X)
|
self.variances.gradient = (dL_dK.dot(X)*X).sum(0) #np.einsum('ij,iq,jq->q', dL_dK, X, X)
|
||||||
else:
|
else:
|
||||||
#product = X[:, None, :] * X2[None, :, :]
|
#product = X[:, None, :] * X2[None, :, :]
|
||||||
#self.variances.gradient = (dL_dK[:, :, None] * product).sum(0).sum(0)
|
#self.variances.gradient = (dL_dK[:, :, None] * product).sum(0).sum(0)
|
||||||
self.variances.gradient = np.einsum('ij,iq,jq->q', dL_dK, X, X2)
|
self.variances.gradient = (dL_dK.dot(X2)*X).sum(0) #np.einsum('ij,iq,jq->q', dL_dK, X, X2)
|
||||||
else:
|
else:
|
||||||
self.variances.gradient = np.sum(self._dot_product(X, X2) * dL_dK)
|
self.variances.gradient = np.sum(self._dot_product(X, X2) * dL_dK)
|
||||||
|
|
||||||
|
|
@ -93,13 +94,15 @@ class Linear(Kern):
|
||||||
|
|
||||||
|
|
||||||
def gradients_X(self, dL_dK, X, X2=None):
|
def gradients_X(self, dL_dK, X, X2=None):
|
||||||
|
if X2 is None: dL_dK = (dL_dK+dL_dK.T)/2
|
||||||
if X2 is None:
|
if X2 is None:
|
||||||
return np.einsum('jq,q,ij->iq', X, 2*self.variances, dL_dK)
|
return dL_dK.dot(X)*(2*self.variances) #np.einsum('jq,q,ij->iq', X, 2*self.variances, dL_dK)
|
||||||
else:
|
else:
|
||||||
#return (((X2[None,:, :] * self.variances)) * dL_dK[:, :, None]).sum(1)
|
#return (((X2[None,:, :] * self.variances)) * dL_dK[:, :, None]).sum(1)
|
||||||
return np.einsum('jq,q,ij->iq', X2, self.variances, dL_dK)
|
return dL_dK.dot(X2)*self.variances #np.einsum('jq,q,ij->iq', X2, self.variances, dL_dK)
|
||||||
|
|
||||||
def gradients_XX(self, dL_dK, X, X2=None):
|
def gradients_XX(self, dL_dK, X, X2=None):
|
||||||
|
if X2 is None: dL_dK = (dL_dK+dL_dK.T)/2
|
||||||
if X2 is None:
|
if X2 is None:
|
||||||
return 2*np.ones(X.shape)*self.variances
|
return 2*np.ones(X.shape)*self.variances
|
||||||
else:
|
else:
|
||||||
|
|
@ -162,6 +165,7 @@ class LinearFull(Kern):
|
||||||
return np.einsum('ij,jk,lk->il', X, P, X if X2 is None else X2)
|
return np.einsum('ij,jk,lk->il', X, P, X if X2 is None else X2)
|
||||||
|
|
||||||
def update_gradients_full(self, dL_dK, X, X2=None):
|
def update_gradients_full(self, dL_dK, X, X2=None):
|
||||||
|
if X2 is None: dL_dK = (dL_dK+dL_dK.T)/2
|
||||||
self.kappa.gradient = np.einsum('ij,ik,kj->j', X, dL_dK, X if X2 is None else X2)
|
self.kappa.gradient = np.einsum('ij,ik,kj->j', X, dL_dK, X if X2 is None else X2)
|
||||||
self.W.gradient = np.einsum('ij,kl,ik,lm->jm', X, X if X2 is None else X2, dL_dK, self.W)
|
self.W.gradient = np.einsum('ij,kl,ik,lm->jm', X, X if X2 is None else X2, dL_dK, self.W)
|
||||||
self.W.gradient += np.einsum('ij,kl,ik,jm->lm', X, X if X2 is None else X2, dL_dK, self.W)
|
self.W.gradient += np.einsum('ij,kl,ik,jm->lm', X, X if X2 is None else X2, dL_dK, self.W)
|
||||||
|
|
@ -175,6 +179,7 @@ class LinearFull(Kern):
|
||||||
self.W.gradient = 2.*np.einsum('ij,ik,jl,i->kl', X, X, self.W, dL_dKdiag)
|
self.W.gradient = 2.*np.einsum('ij,ik,jl,i->kl', X, X, self.W, dL_dKdiag)
|
||||||
|
|
||||||
def gradients_X(self, dL_dK, X, X2=None):
|
def gradients_X(self, dL_dK, X, X2=None):
|
||||||
|
if X2 is None: dL_dK = (dL_dK+dL_dK.T)/2
|
||||||
P = np.dot(self.W, self.W.T) + np.diag(self.kappa)
|
P = np.dot(self.W, self.W.T) + np.diag(self.kappa)
|
||||||
if X2 is None:
|
if X2 is None:
|
||||||
return 2.*np.einsum('ij,jk,kl->il', dL_dK, X, P)
|
return 2.*np.einsum('ij,jk,kl->il', dL_dK, X, P)
|
||||||
|
|
|
||||||
|
|
@ -5,32 +5,49 @@ import numpy as np
|
||||||
from .kern import Kern
|
from .kern import Kern
|
||||||
from ...core.parameterization import Param
|
from ...core.parameterization import Param
|
||||||
from paramz.transformations import Logexp
|
from paramz.transformations import Logexp
|
||||||
|
from paramz.caching import Cache_this
|
||||||
|
|
||||||
class Poly(Kern):
|
class Poly(Kern):
|
||||||
"""
|
"""
|
||||||
Polynomial kernel
|
Polynomial kernel
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, input_dim, variance=1., order=3., active_dims=None, name='poly'):
|
def __init__(self, input_dim, variance=1., scale=1., bias=1., order=3., active_dims=None, name='poly'):
|
||||||
super(Poly, self).__init__(input_dim, active_dims, name)
|
super(Poly, self).__init__(input_dim, active_dims, name)
|
||||||
self.variance = Param('variance', variance, Logexp())
|
self.variance = Param('variance', variance, Logexp())
|
||||||
self.link_parameter(self.variance)
|
self.scale = Param('scale', scale, Logexp())
|
||||||
|
self.bias = Param('bias', bias, Logexp())
|
||||||
|
|
||||||
|
self.link_parameters(self.variance, self.scale, self.bias)
|
||||||
|
assert order >= 1, 'The order of the polynomial has to be at least 1.'
|
||||||
self.order=order
|
self.order=order
|
||||||
|
|
||||||
def K(self, X, X2=None):
|
|
||||||
return (self._dot_product(X, X2) + 1.)**self.order * self.variance
|
|
||||||
|
|
||||||
def _dot_product(self, X, X2=None):
|
def K(self, X, X2=None):
|
||||||
|
_, _, B = self._AB(X, X2)
|
||||||
|
return B * self.variance
|
||||||
|
|
||||||
|
@Cache_this(limit=2)
|
||||||
|
def _AB(self, X, X2=None):
|
||||||
if X2 is None:
|
if X2 is None:
|
||||||
return np.dot(X, X.T)
|
dot_prod = np.dot(X, X.T)
|
||||||
else:
|
else:
|
||||||
return np.dot(X, X2.T)
|
dot_prod = np.dot(X, X2.T)
|
||||||
|
A = (self.scale * dot_prod) + self.bias
|
||||||
|
B = A ** self.order
|
||||||
|
return dot_prod, A, B
|
||||||
|
|
||||||
def Kdiag(self, X):
|
def Kdiag(self, X):
|
||||||
return self.variance*(np.square(X).sum(1) + 1.)**self.order
|
return self.K(X).diagonal()#self.variance*(np.square(X).sum(1) + 1.)**self.order
|
||||||
|
|
||||||
def update_gradients_full(self, dL_dK, X, X2=None):
|
def update_gradients_full(self, dL_dK, X, X2=None):
|
||||||
self.variance.gradient = np.sum(dL_dK * (self._dot_product(X, X2) + 1.)**self.order)
|
dot_prod, A, B = self._AB(X, X2)
|
||||||
|
dK_dA = self.variance * self.order * A ** (self.order-1.)
|
||||||
|
dL_dA = dL_dK * (dK_dA)
|
||||||
|
self.scale.gradient = (dL_dA * dot_prod).sum()
|
||||||
|
self.bias.gradient = dL_dA.sum()
|
||||||
|
self.variance.gradient = np.sum(dL_dK * B)
|
||||||
|
#import ipdb;ipdb.set_trace()
|
||||||
|
|
||||||
def update_gradients_diag(self, dL_dKdiag, X):
|
def update_gradients_diag(self, dL_dKdiag, X):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ from . import PSICOMP
|
||||||
|
|
||||||
class PSICOMP_GH(PSICOMP):
|
class PSICOMP_GH(PSICOMP):
|
||||||
|
|
||||||
def __init__(self, degree=5, cache_K=True):
|
def __init__(self, degree=11, cache_K=True):
|
||||||
self.degree = degree
|
self.degree = degree
|
||||||
self.cache_K = cache_K
|
self.cache_K = cache_K
|
||||||
self.locs, self.weights = np.polynomial.hermite.hermgauss(degree)
|
self.locs, self.weights = np.polynomial.hermite.hermgauss(degree)
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,8 @@ def _psi2compDer(dL_dpsi2, variance, lengthscale, Z, mu, S):
|
||||||
denom = 1./(2*S+lengthscale2)
|
denom = 1./(2*S+lengthscale2)
|
||||||
denom2 = np.square(denom)
|
denom2 = np.square(denom)
|
||||||
|
|
||||||
|
if len(dL_dpsi2.shape)==2: dL_dpsi2 = (dL_dpsi2+dL_dpsi2.T)/2
|
||||||
|
else: dL_dpsi2 = (dL_dpsi2+ np.swapaxes(dL_dpsi2, 1,2))/2
|
||||||
_psi2 = _psi2computations(variance, lengthscale, Z, mu, S) # NxMxM
|
_psi2 = _psi2computations(variance, lengthscale, Z, mu, S) # NxMxM
|
||||||
Lpsi2 = dL_dpsi2*_psi2 # dL_dpsi2 is MxM, using broadcast to multiply N out
|
Lpsi2 = dL_dpsi2*_psi2 # dL_dpsi2 is MxM, using broadcast to multiply N out
|
||||||
Lpsi2sum = Lpsi2.reshape(N,M*M).sum(1) #N
|
Lpsi2sum = Lpsi2.reshape(N,M*M).sum(1) #N
|
||||||
|
|
|
||||||
|
|
@ -360,7 +360,10 @@ class PSICOMP_RBF_GPU(PSICOMP_RBF):
|
||||||
if self.GPU_direct:
|
if self.GPU_direct:
|
||||||
return psi0, psi1_gpu, psi2_gpu
|
return psi0, psi1_gpu, psi2_gpu
|
||||||
else:
|
else:
|
||||||
return psi0, psi1_gpu.get(), psi2_gpu.get()
|
if return_psi2_n:
|
||||||
|
return psi0, psi1_gpu.get(), psi2n_gpu.get()
|
||||||
|
else:
|
||||||
|
return psi0, psi1_gpu.get(), psi2_gpu.get()
|
||||||
|
|
||||||
def psiDerivativecomputations(self, kern, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior):
|
def psiDerivativecomputations(self, kern, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior):
|
||||||
try:
|
try:
|
||||||
|
|
@ -370,6 +373,10 @@ class PSICOMP_RBF_GPU(PSICOMP_RBF):
|
||||||
|
|
||||||
@Cache_this(limit=10, ignore_args=(0,2,3,4))
|
@Cache_this(limit=10, ignore_args=(0,2,3,4))
|
||||||
def _psiDerivativecomputations(self, kern, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior):
|
def _psiDerivativecomputations(self, kern, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior):
|
||||||
|
# resolve the requirement of dL_dpsi2 to be symmetric
|
||||||
|
if len(dL_dpsi2.shape)==2: dL_dpsi2 = (dL_dpsi2+dL_dpsi2.T)/2
|
||||||
|
else: dL_dpsi2 = (dL_dpsi2+ np.swapaxes(dL_dpsi2, 1,2))/2
|
||||||
|
|
||||||
variance, lengthscale = kern.variance, kern.lengthscale
|
variance, lengthscale = kern.variance, kern.lengthscale
|
||||||
from ....util.linalg_gpu import sum_axis
|
from ....util.linalg_gpu import sum_axis
|
||||||
ARD = (len(lengthscale)!=1)
|
ARD = (len(lengthscale)!=1)
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ class Stationary(Kern):
|
||||||
r = self._scaled_dist(X, X2)
|
r = self._scaled_dist(X, X2)
|
||||||
return self.K_of_r(r)
|
return self.K_of_r(r)
|
||||||
|
|
||||||
@Cache_this(limit=20, ignore_args=())
|
@Cache_this(limit=3, ignore_args=())
|
||||||
def dK_dr_via_X(self, X, X2):
|
def dK_dr_via_X(self, X, X2):
|
||||||
#a convenience function, so we can cache dK_dr
|
#a convenience function, so we can cache dK_dr
|
||||||
return self.dK_dr(self._scaled_dist(X, X2))
|
return self.dK_dr(self._scaled_dist(X, X2))
|
||||||
|
|
@ -127,7 +127,7 @@ class Stationary(Kern):
|
||||||
r2 = np.clip(r2, 0, np.inf)
|
r2 = np.clip(r2, 0, np.inf)
|
||||||
return np.sqrt(r2)
|
return np.sqrt(r2)
|
||||||
|
|
||||||
@Cache_this(limit=20, ignore_args=())
|
@Cache_this(limit=3, ignore_args=())
|
||||||
def _scaled_dist(self, X, X2=None):
|
def _scaled_dist(self, X, X2=None):
|
||||||
"""
|
"""
|
||||||
Efficiently compute the scaled distance, r.
|
Efficiently compute the scaled distance, r.
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,14 @@ import numpy as np
|
||||||
import itertools, logging
|
import itertools, logging
|
||||||
|
|
||||||
from ..kern import Kern
|
from ..kern import Kern
|
||||||
from GPy.core.parameterization.variational import NormalPrior
|
from ..core.parameterization.variational import NormalPrior
|
||||||
from ..core.parameterization import Param
|
from ..core.parameterization import Param
|
||||||
from paramz import ObsAr
|
from paramz import ObsAr
|
||||||
from ..inference.latent_function_inference.var_dtc import VarDTC
|
from ..inference.latent_function_inference.var_dtc import VarDTC
|
||||||
from ..inference.latent_function_inference import InferenceMethodList
|
from ..inference.latent_function_inference import InferenceMethodList
|
||||||
from ..likelihoods import Gaussian
|
from ..likelihoods import Gaussian
|
||||||
from ..util.initialization import initialize_latent
|
from ..util.initialization import initialize_latent
|
||||||
from GPy.models.bayesian_gplvm_minibatch import BayesianGPLVMMiniBatch
|
from ..models.bayesian_gplvm_minibatch import BayesianGPLVMMiniBatch
|
||||||
|
|
||||||
class MRD(BayesianGPLVMMiniBatch):
|
class MRD(BayesianGPLVMMiniBatch):
|
||||||
"""
|
"""
|
||||||
|
|
@ -215,40 +215,6 @@ class MRD(BayesianGPLVMMiniBatch):
|
||||||
Z = np.random.randn(self.num_inducing, self.input_dim) * X.var()
|
Z = np.random.randn(self.num_inducing, self.input_dim) * X.var()
|
||||||
return Z
|
return Z
|
||||||
|
|
||||||
def _handle_plotting(self, fignum, axes, plotf, sharex=False, sharey=False):
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
if axes is None:
|
|
||||||
fig = plt.figure(num=fignum)
|
|
||||||
sharex_ax = None
|
|
||||||
sharey_ax = None
|
|
||||||
plots = []
|
|
||||||
for i, g in enumerate(self.bgplvms):
|
|
||||||
try:
|
|
||||||
if sharex:
|
|
||||||
sharex_ax = ax # @UndefinedVariable
|
|
||||||
sharex = False # dont set twice
|
|
||||||
if sharey:
|
|
||||||
sharey_ax = ax # @UndefinedVariable
|
|
||||||
sharey = False # dont set twice
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
if axes is None:
|
|
||||||
ax = fig.add_subplot(1, len(self.bgplvms), i + 1, sharex=sharex_ax, sharey=sharey_ax)
|
|
||||||
elif isinstance(axes, (tuple, list, np.ndarray)):
|
|
||||||
ax = axes[i]
|
|
||||||
else:
|
|
||||||
raise ValueError("Need one axes per latent dimension input_dim")
|
|
||||||
plots.append(plotf(i, g, ax))
|
|
||||||
if sharey_ax is not None:
|
|
||||||
plt.setp(ax.get_yticklabels(), visible=False)
|
|
||||||
plt.draw()
|
|
||||||
if axes is None:
|
|
||||||
try:
|
|
||||||
fig.tight_layout()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
return plots
|
|
||||||
|
|
||||||
def predict(self, Xnew, full_cov=False, Y_metadata=None, kern=None, Yindex=0):
|
def predict(self, Xnew, full_cov=False, Y_metadata=None, kern=None, Yindex=0):
|
||||||
"""
|
"""
|
||||||
Prediction for data set Yindex[default=0].
|
Prediction for data set Yindex[default=0].
|
||||||
|
|
@ -270,59 +236,53 @@ class MRD(BayesianGPLVMMiniBatch):
|
||||||
# sharex=sharex, sharey=sharey)
|
# sharex=sharex, sharey=sharey)
|
||||||
# return fig
|
# return fig
|
||||||
|
|
||||||
def plot_scales(self, fignum=None, ax=None, titles=None, sharex=False, sharey=True, *args, **kwargs):
|
def plot_scales(self, titles=None, fig_kwargs=dict(figsize=None, tight_layout=True), **kwargs):
|
||||||
"""
|
"""
|
||||||
|
Plot input sensitivity for all datasets, to see which input dimensions are
|
||||||
TODO: Explain other parameters
|
significant for which dataset.
|
||||||
|
|
||||||
:param titles: titles for axes of datasets
|
:param titles: titles for axes of datasets
|
||||||
|
|
||||||
|
kwargs go into plot_ARD for each kernel.
|
||||||
"""
|
"""
|
||||||
|
from ..plotting import plotting_library as pl
|
||||||
|
|
||||||
if titles is None:
|
if titles is None:
|
||||||
titles = [r'${}$'.format(name) for name in self.names]
|
titles = [r'${}$'.format(name) for name in self.names]
|
||||||
ymax = reduce(max, [np.ceil(max(g.kern.input_sensitivity())) for g in self.bgplvms])
|
|
||||||
def plotf(i, g, ax):
|
M = len(self.bgplvms)
|
||||||
#ax.set_ylim([0,ymax])
|
fig = pl().figure(rows=1, cols=M, **fig_kwargs)
|
||||||
return g.kern.plot_ARD(ax=ax, title=titles[i], *args, **kwargs)
|
plots = {}
|
||||||
fig = self._handle_plotting(fignum, ax, plotf, sharex=sharex, sharey=sharey)
|
for c in range(M):
|
||||||
return fig
|
canvas = self.bgplvms[c].kern.plot_ARD(title=titles[c], figure=fig, col=c+1, **kwargs)
|
||||||
|
plots[titles[c]] = canvas
|
||||||
|
pl().show_canvas(canvas)
|
||||||
|
return plots
|
||||||
|
|
||||||
def plot_latent(self, labels=None, which_indices=None,
|
def plot_latent(self, labels=None, which_indices=None,
|
||||||
resolution=50, ax=None, marker='o', s=40,
|
resolution=60, legend=True,
|
||||||
fignum=None, plot_inducing=True, legend=True,
|
|
||||||
plot_limits=None,
|
plot_limits=None,
|
||||||
aspect='auto', updates=False, predict_kwargs={}, imshow_kwargs={}):
|
updates=False,
|
||||||
|
kern=None, marker='<>^vsd',
|
||||||
|
num_samples=1000, projection='2d',
|
||||||
|
predict_kwargs={},
|
||||||
|
scatter_kwargs=None, **imshow_kwargs):
|
||||||
"""
|
"""
|
||||||
see plotting.matplot_dep.dim_reduction_plots.plot_latent
|
see plotting.matplot_dep.dim_reduction_plots.plot_latent
|
||||||
if predict_kwargs is None, will plot latent spaces for 0th dataset (and kernel), otherwise give
|
if predict_kwargs is None, will plot latent spaces for 0th dataset (and kernel), otherwise give
|
||||||
predict_kwargs=dict(Yindex='index') for plotting only the latent space of dataset with 'index'.
|
predict_kwargs=dict(Yindex='index') for plotting only the latent space of dataset with 'index'.
|
||||||
"""
|
"""
|
||||||
import sys
|
from ..plotting.gpy_plot.latent_plots import plot_latent
|
||||||
assert "matplotlib" in sys.modules, "matplotlib package has not been imported."
|
|
||||||
from matplotlib import pyplot as plt
|
|
||||||
from ..plotting.matplot_dep import dim_reduction_plots
|
|
||||||
if "Yindex" not in predict_kwargs:
|
if "Yindex" not in predict_kwargs:
|
||||||
predict_kwargs['Yindex'] = 0
|
predict_kwargs['Yindex'] = 0
|
||||||
|
|
||||||
Yindex = predict_kwargs['Yindex']
|
Yindex = predict_kwargs['Yindex']
|
||||||
if ax is None:
|
|
||||||
fig = plt.figure(num=fignum)
|
|
||||||
ax = fig.add_subplot(111)
|
|
||||||
else:
|
|
||||||
fig = ax.figure
|
|
||||||
self.kern = self.bgplvms[Yindex].kern
|
self.kern = self.bgplvms[Yindex].kern
|
||||||
self.likelihood = self.bgplvms[Yindex].likelihood
|
self.likelihood = self.bgplvms[Yindex].likelihood
|
||||||
plot = dim_reduction_plots.plot_latent(self, labels, which_indices,
|
|
||||||
resolution, ax, marker, s,
|
|
||||||
fignum, plot_inducing, legend,
|
|
||||||
plot_limits, aspect, updates, predict_kwargs, imshow_kwargs)
|
|
||||||
ax.set_title(self.bgplvms[Yindex].name)
|
|
||||||
try:
|
|
||||||
fig.tight_layout()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return plot
|
return plot_latent(self, labels, which_indices, resolution, legend, plot_limits, updates, kern, marker, num_samples, projection, scatter_kwargs)
|
||||||
|
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
state = super(MRD, self).__getstate__()
|
state = super(MRD, self).__getstate__()
|
||||||
|
|
|
||||||
|
|
@ -191,3 +191,37 @@ class SSGPLVM(SparseGP_MPI):
|
||||||
return self.kern.input_sensitivity()
|
return self.kern.input_sensitivity()
|
||||||
else:
|
else:
|
||||||
return self.variational_prior.pi
|
return self.variational_prior.pi
|
||||||
|
|
||||||
|
def sample_W(self, nSamples, raw_samples=False):
|
||||||
|
"""
|
||||||
|
Sample the loading matrix if the kernel is linear.
|
||||||
|
"""
|
||||||
|
assert isinstance(self.kern, kern.Linear)
|
||||||
|
from ..util.linalg import pdinv
|
||||||
|
N, D = self.Y.shape
|
||||||
|
Q = self.X.shape[1]
|
||||||
|
noise_var = self.likelihood.variance.values
|
||||||
|
|
||||||
|
# Draw samples for X
|
||||||
|
Xs = np.random.randn(*((nSamples,)+self.X.shape))*np.sqrt(self.X.variance.values)+self.X.mean.values
|
||||||
|
b = np.random.rand(*((nSamples,)+self.X.shape))
|
||||||
|
Xs[b>self.X.gamma.values] = 0
|
||||||
|
|
||||||
|
invcov = (Xs[:,:,:,None]*Xs[:,:,None,:]).sum(1)/noise_var+np.eye(Q)
|
||||||
|
cov = np.array([pdinv(invcov[s_idx])[0] for s_idx in xrange(invcov.shape[0])])
|
||||||
|
Ws = np.empty((nSamples, Q, D))
|
||||||
|
tmp = (np.transpose(Xs, (0,2,1)).reshape(nSamples*Q,N).dot(self.Y)).reshape(nSamples,Q,D)
|
||||||
|
mean = (cov[:,:,:,None]*tmp[:,None,:,:]).sum(2)/noise_var
|
||||||
|
zeros = np.zeros((Q,))
|
||||||
|
for s_idx in xrange(Xs.shape[0]):
|
||||||
|
Ws[s_idx] = (np.random.multivariate_normal(mean=zeros,cov=cov[s_idx],size=(D,))).T+mean[s_idx]
|
||||||
|
|
||||||
|
if raw_samples:
|
||||||
|
return Ws
|
||||||
|
else:
|
||||||
|
return Ws.mean(0), Ws.std(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,18 +25,66 @@ def change_plotting_library(lib):
|
||||||
current_lib[0] = PlotlyPlots()
|
current_lib[0] = PlotlyPlots()
|
||||||
if lib == 'none':
|
if lib == 'none':
|
||||||
current_lib[0] = None
|
current_lib[0] = None
|
||||||
|
inject_plotting()
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
except (ImportError, NameError):
|
except (ImportError, NameError):
|
||||||
config.set('plotting', 'library', 'none')
|
config.set('plotting', 'library', 'none')
|
||||||
|
raise
|
||||||
import warnings
|
import warnings
|
||||||
warnings.warn(ImportWarning("You spevified {} in your configuration, but is not available. Install newest version of {} for plotting".format(lib, lib)))
|
warnings.warn(ImportWarning("You spevified {} in your configuration, but is not available. Install newest version of {} for plotting".format(lib, lib)))
|
||||||
|
|
||||||
from ..util.config import config, NoOptionError
|
def inject_plotting():
|
||||||
try:
|
if current_lib[0] is not None:
|
||||||
lib = config.get('plotting', 'library')
|
# Inject the plots into classes here:
|
||||||
change_plotting_library(lib)
|
|
||||||
except NoOptionError:
|
# Already converted to new style:
|
||||||
print("No plotting library was specified in config file. \n{}".format(error_suggestion))
|
from . import gpy_plot
|
||||||
|
|
||||||
|
from ..core import GP
|
||||||
|
GP.plot_data = gpy_plot.data_plots.plot_data
|
||||||
|
GP.plot_data_error = gpy_plot.data_plots.plot_data_error
|
||||||
|
GP.plot_errorbars_trainset = gpy_plot.data_plots.plot_errorbars_trainset
|
||||||
|
GP.plot_mean = gpy_plot.gp_plots.plot_mean
|
||||||
|
GP.plot_confidence = gpy_plot.gp_plots.plot_confidence
|
||||||
|
GP.plot_density = gpy_plot.gp_plots.plot_density
|
||||||
|
GP.plot_samples = gpy_plot.gp_plots.plot_samples
|
||||||
|
GP.plot = gpy_plot.gp_plots.plot
|
||||||
|
GP.plot_f = gpy_plot.gp_plots.plot_f
|
||||||
|
GP.plot_magnification = gpy_plot.latent_plots.plot_magnification
|
||||||
|
|
||||||
|
from ..core import SparseGP
|
||||||
|
SparseGP.plot_inducing = gpy_plot.data_plots.plot_inducing
|
||||||
|
|
||||||
|
from ..models import GPLVM, BayesianGPLVM, bayesian_gplvm_minibatch, SSGPLVM, SSMRD
|
||||||
|
GPLVM.plot_latent = gpy_plot.latent_plots.plot_latent
|
||||||
|
GPLVM.plot_scatter = gpy_plot.latent_plots.plot_latent_scatter
|
||||||
|
GPLVM.plot_inducing = gpy_plot.latent_plots.plot_latent_inducing
|
||||||
|
GPLVM.plot_steepest_gradient_map = gpy_plot.latent_plots.plot_steepest_gradient_map
|
||||||
|
BayesianGPLVM.plot_latent = gpy_plot.latent_plots.plot_latent
|
||||||
|
BayesianGPLVM.plot_scatter = gpy_plot.latent_plots.plot_latent_scatter
|
||||||
|
BayesianGPLVM.plot_inducing = gpy_plot.latent_plots.plot_latent_inducing
|
||||||
|
BayesianGPLVM.plot_steepest_gradient_map = gpy_plot.latent_plots.plot_steepest_gradient_map
|
||||||
|
bayesian_gplvm_minibatch.BayesianGPLVMMiniBatch.plot_latent = gpy_plot.latent_plots.plot_latent
|
||||||
|
bayesian_gplvm_minibatch.BayesianGPLVMMiniBatch.plot_scatter = gpy_plot.latent_plots.plot_latent_scatter
|
||||||
|
bayesian_gplvm_minibatch.BayesianGPLVMMiniBatch.plot_inducing = gpy_plot.latent_plots.plot_latent_inducing
|
||||||
|
bayesian_gplvm_minibatch.BayesianGPLVMMiniBatch.plot_steepest_gradient_map = gpy_plot.latent_plots.plot_steepest_gradient_map
|
||||||
|
SSGPLVM.plot_latent = gpy_plot.latent_plots.plot_latent
|
||||||
|
SSGPLVM.plot_scatter = gpy_plot.latent_plots.plot_latent_scatter
|
||||||
|
SSGPLVM.plot_inducing = gpy_plot.latent_plots.plot_latent_inducing
|
||||||
|
SSGPLVM.plot_steepest_gradient_map = gpy_plot.latent_plots.plot_steepest_gradient_map
|
||||||
|
|
||||||
|
from ..kern import Kern
|
||||||
|
Kern.plot_covariance = gpy_plot.kernel_plots.plot_covariance
|
||||||
|
def deprecate_plot(self, *args, **kwargs):
|
||||||
|
import warnings
|
||||||
|
warnings.warn(DeprecationWarning('Kern.plot is being deprecated and will not be available in the 1.0 release. Use Kern.plot_covariance instead'))
|
||||||
|
return self.plot_covariance(*args, **kwargs)
|
||||||
|
Kern.plot = deprecate_plot
|
||||||
|
Kern.plot_ARD = gpy_plot.kernel_plots.plot_ARD
|
||||||
|
|
||||||
|
from ..inference.optimization import Optimizer
|
||||||
|
Optimizer.plot = gpy_plot.inference_plots.plot_optimizer
|
||||||
|
# Variational plot!
|
||||||
|
|
||||||
def plotting_library():
|
def plotting_library():
|
||||||
if current_lib[0] is None:
|
if current_lib[0] is None:
|
||||||
|
|
@ -53,54 +101,10 @@ def show(figure, **kwargs):
|
||||||
"""
|
"""
|
||||||
return plotting_library().show_canvas(figure, **kwargs)
|
return plotting_library().show_canvas(figure, **kwargs)
|
||||||
|
|
||||||
if config.get('plotting', 'library') is not 'none':
|
|
||||||
# Inject the plots into classes here:
|
|
||||||
|
|
||||||
# Already converted to new style:
|
from ..util.config import config, NoOptionError
|
||||||
from . import gpy_plot
|
try:
|
||||||
|
lib = config.get('plotting', 'library')
|
||||||
from ..core import GP
|
change_plotting_library(lib)
|
||||||
GP.plot_data = gpy_plot.data_plots.plot_data
|
except NoOptionError:
|
||||||
GP.plot_data_error = gpy_plot.data_plots.plot_data_error
|
print("No plotting library was specified in config file. \n{}".format(error_suggestion))
|
||||||
GP.plot_errorbars_trainset = gpy_plot.data_plots.plot_errorbars_trainset
|
|
||||||
GP.plot_mean = gpy_plot.gp_plots.plot_mean
|
|
||||||
GP.plot_confidence = gpy_plot.gp_plots.plot_confidence
|
|
||||||
GP.plot_density = gpy_plot.gp_plots.plot_density
|
|
||||||
GP.plot_samples = gpy_plot.gp_plots.plot_samples
|
|
||||||
GP.plot = gpy_plot.gp_plots.plot
|
|
||||||
GP.plot_f = gpy_plot.gp_plots.plot_f
|
|
||||||
GP.plot_magnification = gpy_plot.latent_plots.plot_magnification
|
|
||||||
|
|
||||||
from ..core import SparseGP
|
|
||||||
SparseGP.plot_inducing = gpy_plot.data_plots.plot_inducing
|
|
||||||
|
|
||||||
from ..models import GPLVM, BayesianGPLVM, bayesian_gplvm_minibatch, SSGPLVM, SSMRD
|
|
||||||
GPLVM.plot_latent = gpy_plot.latent_plots.plot_latent
|
|
||||||
GPLVM.plot_scatter = gpy_plot.latent_plots.plot_latent_scatter
|
|
||||||
GPLVM.plot_inducing = gpy_plot.latent_plots.plot_latent_inducing
|
|
||||||
GPLVM.plot_steepest_gradient_map = gpy_plot.latent_plots.plot_steepest_gradient_map
|
|
||||||
BayesianGPLVM.plot_latent = gpy_plot.latent_plots.plot_latent
|
|
||||||
BayesianGPLVM.plot_scatter = gpy_plot.latent_plots.plot_latent_scatter
|
|
||||||
BayesianGPLVM.plot_inducing = gpy_plot.latent_plots.plot_latent_inducing
|
|
||||||
BayesianGPLVM.plot_steepest_gradient_map = gpy_plot.latent_plots.plot_steepest_gradient_map
|
|
||||||
bayesian_gplvm_minibatch.BayesianGPLVMMiniBatch.plot_latent = gpy_plot.latent_plots.plot_latent
|
|
||||||
bayesian_gplvm_minibatch.BayesianGPLVMMiniBatch.plot_scatter = gpy_plot.latent_plots.plot_latent_scatter
|
|
||||||
bayesian_gplvm_minibatch.BayesianGPLVMMiniBatch.plot_inducing = gpy_plot.latent_plots.plot_latent_inducing
|
|
||||||
bayesian_gplvm_minibatch.BayesianGPLVMMiniBatch.plot_steepest_gradient_map = gpy_plot.latent_plots.plot_steepest_gradient_map
|
|
||||||
SSGPLVM.plot_latent = gpy_plot.latent_plots.plot_latent
|
|
||||||
SSGPLVM.plot_scatter = gpy_plot.latent_plots.plot_latent_scatter
|
|
||||||
SSGPLVM.plot_inducing = gpy_plot.latent_plots.plot_latent_inducing
|
|
||||||
SSGPLVM.plot_steepest_gradient_map = gpy_plot.latent_plots.plot_steepest_gradient_map
|
|
||||||
|
|
||||||
from ..kern import Kern
|
|
||||||
Kern.plot_covariance = gpy_plot.kernel_plots.plot_covariance
|
|
||||||
def deprecate_plot(self, *args, **kwargs):
|
|
||||||
import warnings
|
|
||||||
warnings.warn(DeprecationWarning('Kern.plot is being deprecated and will not be available in the 1.0 release. Use Kern.plot_covariance instead'))
|
|
||||||
return self.plot_covariance(*args, **kwargs)
|
|
||||||
Kern.plot = deprecate_plot
|
|
||||||
Kern.plot_ARD = gpy_plot.kernel_plots.plot_ARD
|
|
||||||
|
|
||||||
from ..inference.optimization import Optimizer
|
|
||||||
Optimizer.plot = gpy_plot.inference_plots.plot_optimizer
|
|
||||||
# Variational plot!
|
|
||||||
|
|
@ -91,7 +91,7 @@ def _plot_mean(self, canvas, helper_data, helper_prediction,
|
||||||
if projection == '2d':
|
if projection == '2d':
|
||||||
update_not_existing_kwargs(kwargs, pl().defaults.meanplot_2d) # @UndefinedVariable
|
update_not_existing_kwargs(kwargs, pl().defaults.meanplot_2d) # @UndefinedVariable
|
||||||
plots = dict(gpmean=[pl().contour(canvas, x[:,0], y[0,:],
|
plots = dict(gpmean=[pl().contour(canvas, x[:,0], y[0,:],
|
||||||
mu.reshape(resolution, resolution),
|
mu.reshape(resolution, resolution).T,
|
||||||
levels=levels, label=label, **kwargs)])
|
levels=levels, label=label, **kwargs)])
|
||||||
elif projection == '3d':
|
elif projection == '3d':
|
||||||
update_not_existing_kwargs(kwargs, pl().defaults.meanplot_3d) # @UndefinedVariable
|
update_not_existing_kwargs(kwargs, pl().defaults.meanplot_3d) # @UndefinedVariable
|
||||||
|
|
@ -319,9 +319,17 @@ def plot(self, plot_limits=None, fixed_inputs=None,
|
||||||
:param {2d|3d} projection: plot in 2d or 3d?
|
:param {2d|3d} projection: plot in 2d or 3d?
|
||||||
:param bool legend: convenience, whether to put a legend on the plot or not.
|
:param bool legend: convenience, whether to put a legend on the plot or not.
|
||||||
"""
|
"""
|
||||||
canvas, _ = pl().new_canvas(projection=projection, **kwargs)
|
|
||||||
X = get_x_y_var(self)[0]
|
X = get_x_y_var(self)[0]
|
||||||
helper_data = helper_for_plot_data(self, X, plot_limits, visible_dims, fixed_inputs, resolution)
|
helper_data = helper_for_plot_data(self, X, plot_limits, visible_dims, fixed_inputs, resolution)
|
||||||
|
xmin, xmax = helper_data[5:7]
|
||||||
|
free_dims = helper_data[1]
|
||||||
|
|
||||||
|
if not 'xlim' in kwargs:
|
||||||
|
kwargs['xlim'] = (xmin[0], xmax[0])
|
||||||
|
if not 'ylim' in kwargs and len(free_dims) == 2:
|
||||||
|
kwargs['ylim'] = (xmin[1], xmax[1])
|
||||||
|
|
||||||
|
canvas, _ = pl().new_canvas(projection=projection, **kwargs)
|
||||||
helper_prediction = helper_predict_with_model(self, helper_data[2], plot_raw,
|
helper_prediction = helper_predict_with_model(self, helper_data[2], plot_raw,
|
||||||
apply_link, np.linspace(2.5, 97.5, levels*2) if plot_density else (lower,upper),
|
apply_link, np.linspace(2.5, 97.5, levels*2) if plot_density else (lower,upper),
|
||||||
get_which_data_ycols(self, which_data_ycols),
|
get_which_data_ycols(self, which_data_ycols),
|
||||||
|
|
@ -330,9 +338,11 @@ def plot(self, plot_limits=None, fixed_inputs=None,
|
||||||
# It does not make sense to plot the data (which lives not in the latent function space) into latent function space.
|
# It does not make sense to plot the data (which lives not in the latent function space) into latent function space.
|
||||||
plot_data = False
|
plot_data = False
|
||||||
plots = {}
|
plots = {}
|
||||||
|
if hasattr(self, 'Z') and plot_inducing:
|
||||||
|
plots.update(_plot_inducing(self, canvas, visible_dims, projection, 'Inducing'))
|
||||||
if plot_data:
|
if plot_data:
|
||||||
plots.update(_plot_data(self, canvas, which_data_rows, which_data_ycols, visible_dims, projection, "Data"))
|
plots.update(_plot_data(self, canvas, which_data_rows, which_data_ycols, free_dims, projection, "Data"))
|
||||||
plots.update(_plot_data_error(self, canvas, which_data_rows, which_data_ycols, visible_dims, projection, "Data Error"))
|
plots.update(_plot_data_error(self, canvas, which_data_rows, which_data_ycols, free_dims, projection, "Data Error"))
|
||||||
plots.update(_plot(self, canvas, plots, helper_data, helper_prediction, levels, plot_inducing, plot_density, projection))
|
plots.update(_plot(self, canvas, plots, helper_data, helper_prediction, levels, plot_inducing, plot_density, projection))
|
||||||
if plot_raw and (samples_likelihood > 0):
|
if plot_raw and (samples_likelihood > 0):
|
||||||
helper_prediction = helper_predict_with_model(self, helper_data[2], False,
|
helper_prediction = helper_predict_with_model(self, helper_data[2], False,
|
||||||
|
|
@ -340,8 +350,6 @@ def plot(self, plot_limits=None, fixed_inputs=None,
|
||||||
get_which_data_ycols(self, which_data_ycols),
|
get_which_data_ycols(self, which_data_ycols),
|
||||||
predict_kw, samples_likelihood)
|
predict_kw, samples_likelihood)
|
||||||
plots.update(_plot_samples(canvas, helper_data, helper_prediction, projection, "Lik Samples"))
|
plots.update(_plot_samples(canvas, helper_data, helper_prediction, projection, "Lik Samples"))
|
||||||
if hasattr(self, 'Z') and plot_inducing:
|
|
||||||
plots.update(_plot_inducing(self, canvas, visible_dims, projection, 'Inducing'))
|
|
||||||
return pl().add_to_canvas(canvas, plots, legend=legend)
|
return pl().add_to_canvas(canvas, plots, legend=legend)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -389,7 +397,7 @@ def plot_f(self, plot_limits=None, fixed_inputs=None,
|
||||||
:param dict error_kwargs: kwargs for the error plot for the plotting library you are using
|
:param dict error_kwargs: kwargs for the error plot for the plotting library you are using
|
||||||
:param kwargs plot_kwargs: kwargs for the data plot for the plotting library you are using
|
:param kwargs plot_kwargs: kwargs for the data plot for the plotting library you are using
|
||||||
"""
|
"""
|
||||||
plot(self, plot_limits, fixed_inputs, resolution, True,
|
return plot(self, plot_limits, fixed_inputs, resolution, True,
|
||||||
apply_link, which_data_ycols, which_data_rows,
|
apply_link, which_data_ycols, which_data_rows,
|
||||||
visible_dims, levels, samples, 0,
|
visible_dims, levels, samples, 0,
|
||||||
lower, upper, plot_data, plot_inducing,
|
lower, upper, plot_data, plot_inducing,
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ from .. import Tango
|
||||||
from .plot_util import update_not_existing_kwargs, helper_for_plot_data
|
from .plot_util import update_not_existing_kwargs, helper_for_plot_data
|
||||||
from ...kern.src.kern import Kern, CombinationKernel
|
from ...kern.src.kern import Kern, CombinationKernel
|
||||||
|
|
||||||
def plot_ARD(kernel, filtering=None, legend=False, **kwargs):
|
def plot_ARD(kernel, filtering=None, legend=False, canvas=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
If an ARD kernel is present, plot a bar representation using matplotlib
|
If an ARD kernel is present, plot a bar representation using matplotlib
|
||||||
|
|
||||||
|
|
@ -62,7 +62,11 @@ def plot_ARD(kernel, filtering=None, legend=False, **kwargs):
|
||||||
|
|
||||||
bars = []
|
bars = []
|
||||||
kwargs = update_not_existing_kwargs(kwargs, pl().defaults.ard)
|
kwargs = update_not_existing_kwargs(kwargs, pl().defaults.ard)
|
||||||
canvas, kwargs = pl().new_canvas(xlim=(-.5, kernel._effective_input_dim-.5), xlabel='input dimension', ylabel='sensitivity', **kwargs)
|
|
||||||
|
|
||||||
|
if canvas is None:
|
||||||
|
canvas, kwargs = pl().new_canvas(xlim=(-.5, kernel._effective_input_dim-.5), xlabel='input dimension', ylabel='sensitivity', **kwargs)
|
||||||
|
|
||||||
for i in range(ard_params.shape[0]):
|
for i in range(ard_params.shape[0]):
|
||||||
if parts[i].name in filtering:
|
if parts[i].name in filtering:
|
||||||
c = Tango.nextMedium()
|
c = Tango.nextMedium()
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,17 @@ def _wait_for_updates(view, updates):
|
||||||
# No updateable view:
|
# No updateable view:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _new_canvas(self, projection, kwargs, which_indices):
|
||||||
|
input_1, input_2, input_3 = sig_dims = self.get_most_significant_input_dimensions(which_indices)
|
||||||
|
|
||||||
|
if input_3 is None:
|
||||||
|
zlabel = None
|
||||||
|
else:
|
||||||
|
zlabel = 'latent dimension %i' % input_3
|
||||||
|
canvas, kwargs = pl().new_canvas(projection=projection, xlabel='latent dimension %i' % input_1,
|
||||||
|
ylabel='latent dimension %i' % input_2,
|
||||||
|
zlabel=zlabel, **kwargs)
|
||||||
|
return canvas, projection, kwargs, sig_dims
|
||||||
|
|
||||||
def _plot_latent_scatter(canvas, X, visible_dims, labels, marker, num_samples, projection='2d', **kwargs):
|
def _plot_latent_scatter(canvas, X, visible_dims, labels, marker, num_samples, projection='2d', **kwargs):
|
||||||
from .. import Tango
|
from .. import Tango
|
||||||
|
|
@ -85,12 +96,8 @@ def plot_latent_scatter(self, labels=None,
|
||||||
:param str marker: markers to use - cycle if more labels then markers are given
|
:param str marker: markers to use - cycle if more labels then markers are given
|
||||||
:param kwargs: the kwargs for the scatter plots
|
:param kwargs: the kwargs for the scatter plots
|
||||||
"""
|
"""
|
||||||
input_1, input_2, input_3 = sig_dims = self.get_most_significant_input_dimensions(which_indices)
|
canvas, projection, kwargs, sig_dims = _new_canvas(self, projection, kwargs, which_indices)
|
||||||
|
|
||||||
canvas, kwargs = pl().new_canvas(projection=projection,
|
|
||||||
xlabel='latent dimension %i' % input_1,
|
|
||||||
ylabel='latent dimension %i' % input_2,
|
|
||||||
zlabel='latent dimension %i' % input_3, **kwargs)
|
|
||||||
X, _, _ = get_x_y_var(self)
|
X, _, _ = get_x_y_var(self)
|
||||||
if labels is None:
|
if labels is None:
|
||||||
labels = np.ones(self.num_data)
|
labels = np.ones(self.num_data)
|
||||||
|
|
@ -101,8 +108,6 @@ def plot_latent_scatter(self, labels=None,
|
||||||
return pl().add_to_canvas(canvas, dict(scatter=scatters), legend=legend)
|
return pl().add_to_canvas(canvas, dict(scatter=scatters), legend=legend)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def plot_latent_inducing(self,
|
def plot_latent_inducing(self,
|
||||||
which_indices=None,
|
which_indices=None,
|
||||||
legend=False,
|
legend=False,
|
||||||
|
|
@ -122,17 +127,8 @@ def plot_latent_inducing(self,
|
||||||
:param str marker: markers to use - cycle if more labels then markers are given
|
:param str marker: markers to use - cycle if more labels then markers are given
|
||||||
:param kwargs: the kwargs for the scatter plots
|
:param kwargs: the kwargs for the scatter plots
|
||||||
"""
|
"""
|
||||||
input_1, input_2, input_3 = sig_dims = self.get_most_significant_input_dimensions(which_indices)
|
canvas, projection, kwargs, sig_dims = _new_canvas(self, projection, kwargs, which_indices)
|
||||||
if input_3 is None: zlabel=None
|
|
||||||
else: zlabel = 'latent dimension %i' % input_3
|
|
||||||
|
|
||||||
|
|
||||||
if 'color' not in kwargs:
|
|
||||||
kwargs['color'] = 'white'
|
|
||||||
canvas, kwargs = pl().new_canvas(projection=projection,
|
|
||||||
xlabel='latent dimension %i' % input_1,
|
|
||||||
ylabel='latent dimension %i' % input_2,
|
|
||||||
zlabel=zlabel, **kwargs)
|
|
||||||
Z = self.Z.values
|
Z = self.Z.values
|
||||||
labels = np.array(['inducing'] * Z.shape[0])
|
labels = np.array(['inducing'] * Z.shape[0])
|
||||||
scatters = _plot_latent_scatter(canvas, Z, sig_dims, labels, marker, num_samples, projection=projection, **kwargs)
|
scatters = _plot_latent_scatter(canvas, Z, sig_dims, labels, marker, num_samples, projection=projection, **kwargs)
|
||||||
|
|
@ -167,7 +163,8 @@ def plot_magnification(self, labels=None, which_indices=None,
|
||||||
updates=False,
|
updates=False,
|
||||||
mean=True, covariance=True,
|
mean=True, covariance=True,
|
||||||
kern=None, num_samples=1000,
|
kern=None, num_samples=1000,
|
||||||
scatter_kwargs=None, **imshow_kwargs):
|
scatter_kwargs=None, plot_scatter=True,
|
||||||
|
**imshow_kwargs):
|
||||||
"""
|
"""
|
||||||
Plot the magnification factor of the GP on the inputs. This is the
|
Plot the magnification factor of the GP on the inputs. This is the
|
||||||
density of the GP as a gray scale.
|
density of the GP as a gray scale.
|
||||||
|
|
@ -192,17 +189,20 @@ def plot_magnification(self, labels=None, which_indices=None,
|
||||||
_, _, Xgrid, _, _, xmin, xmax, resolution = helper_for_plot_data(self, X, plot_limits, which_indices, None, resolution)
|
_, _, Xgrid, _, _, xmin, xmax, resolution = helper_for_plot_data(self, X, plot_limits, which_indices, None, resolution)
|
||||||
canvas, imshow_kwargs = pl().new_canvas(xlim=(xmin[0], xmax[0]), ylim=(xmin[1], xmax[1]),
|
canvas, imshow_kwargs = pl().new_canvas(xlim=(xmin[0], xmax[0]), ylim=(xmin[1], xmax[1]),
|
||||||
xlabel='latent dimension %i' % input_1, ylabel='latent dimension %i' % input_2, **imshow_kwargs)
|
xlabel='latent dimension %i' % input_1, ylabel='latent dimension %i' % input_2, **imshow_kwargs)
|
||||||
if (labels is not None):
|
plots = {}
|
||||||
legend = find_best_layout_for_subplots(len(np.unique(labels)))[1]
|
if legend and plot_scatter:
|
||||||
else:
|
if (labels is not None):
|
||||||
labels = np.ones(self.num_data)
|
legend = find_best_layout_for_subplots(len(np.unique(labels)))[1]
|
||||||
legend = False
|
else:
|
||||||
scatters = _plot_latent_scatter(canvas, X, which_indices, labels, marker, num_samples, projection='2d', **scatter_kwargs or {})
|
labels = np.ones(self.num_data)
|
||||||
view = _plot_magnification(self, canvas, which_indices, Xgrid, xmin, xmax, resolution, updates, mean, covariance, kern, **imshow_kwargs)
|
legend = False
|
||||||
retval = pl().add_to_canvas(canvas, dict(scatter=scatters, imshow=view),
|
if plot_scatter:
|
||||||
|
plots['scatters'] = _plot_latent_scatter(canvas, X, which_indices, labels, marker, num_samples, projection='2d', **scatter_kwargs or {})
|
||||||
|
plots['view'] = _plot_magnification(self, canvas, which_indices, Xgrid, xmin, xmax, resolution, updates, mean, covariance, kern, **imshow_kwargs)
|
||||||
|
retval = pl().add_to_canvas(canvas, plots,
|
||||||
legend=legend,
|
legend=legend,
|
||||||
)
|
)
|
||||||
_wait_for_updates(view, updates)
|
_wait_for_updates(plots['view'], updates)
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -231,7 +231,7 @@ def plot_latent(self, labels=None, which_indices=None,
|
||||||
plot_limits=None,
|
plot_limits=None,
|
||||||
updates=False,
|
updates=False,
|
||||||
kern=None, marker='<>^vsd',
|
kern=None, marker='<>^vsd',
|
||||||
num_samples=1000,
|
num_samples=1000, projection='2d',
|
||||||
scatter_kwargs=None, **imshow_kwargs):
|
scatter_kwargs=None, **imshow_kwargs):
|
||||||
"""
|
"""
|
||||||
Plot the latent space of the GP on the inputs. This is the
|
Plot the latent space of the GP on the inputs. This is the
|
||||||
|
|
@ -251,16 +251,19 @@ def plot_latent(self, labels=None, which_indices=None,
|
||||||
:param imshow_kwargs: the kwargs for the imshow (magnification factor)
|
:param imshow_kwargs: the kwargs for the imshow (magnification factor)
|
||||||
:param scatter_kwargs: the kwargs for the scatter plots
|
:param scatter_kwargs: the kwargs for the scatter plots
|
||||||
"""
|
"""
|
||||||
|
if projection != '2d':
|
||||||
|
raise ValueError('Cannot plot latent in other then 2 dimensions, consider plot_scatter')
|
||||||
input_1, input_2 = which_indices = self.get_most_significant_input_dimensions(which_indices)[:2]
|
input_1, input_2 = which_indices = self.get_most_significant_input_dimensions(which_indices)[:2]
|
||||||
X = get_x_y_var(self)[0]
|
X = get_x_y_var(self)[0]
|
||||||
_, _, Xgrid, _, _, xmin, xmax, resolution = helper_for_plot_data(self, X, plot_limits, which_indices, None, resolution)
|
_, _, Xgrid, _, _, xmin, xmax, resolution = helper_for_plot_data(self, X, plot_limits, which_indices, None, resolution)
|
||||||
canvas, imshow_kwargs = pl().new_canvas(xlim=(xmin[0], xmax[0]), ylim=(xmin[1], xmax[1]),
|
canvas, imshow_kwargs = pl().new_canvas(xlim=(xmin[0], xmax[0]), ylim=(xmin[1], xmax[1]),
|
||||||
xlabel='latent dimension %i' % input_1, ylabel='latent dimension %i' % input_2, **imshow_kwargs)
|
xlabel='latent dimension %i' % input_1, ylabel='latent dimension %i' % input_2, **imshow_kwargs)
|
||||||
if (labels is not None):
|
if legend:
|
||||||
legend = find_best_layout_for_subplots(len(np.unique(labels)))[1]
|
if (labels is not None):
|
||||||
else:
|
legend = find_best_layout_for_subplots(len(np.unique(labels)))[1]
|
||||||
labels = np.ones(self.num_data)
|
else:
|
||||||
legend = False
|
labels = np.ones(self.num_data)
|
||||||
|
legend = False
|
||||||
scatters = _plot_latent_scatter(canvas, X, which_indices, labels, marker, num_samples, projection='2d', **scatter_kwargs or {})
|
scatters = _plot_latent_scatter(canvas, X, which_indices, labels, marker, num_samples, projection='2d', **scatter_kwargs or {})
|
||||||
view = _plot_latent(self, canvas, which_indices, Xgrid, xmin, xmax, resolution, updates, kern, **imshow_kwargs)
|
view = _plot_latent(self, canvas, which_indices, Xgrid, xmin, xmax, resolution, updates, kern, **imshow_kwargs)
|
||||||
retval = pl().add_to_canvas(canvas, dict(scatter=scatters, imshow=view), legend=legend)
|
retval = pl().add_to_canvas(canvas, dict(scatter=scatters, imshow=view), legend=legend)
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,7 @@ def subsample_X(X, labels, num_samples=1000):
|
||||||
num_samples and the returned subsampled X.
|
num_samples and the returned subsampled X.
|
||||||
"""
|
"""
|
||||||
if X.shape[0] > num_samples:
|
if X.shape[0] > num_samples:
|
||||||
print("Warning: subsampling X, as it has more samples then 1000. X.shape={!s}".format(X.shape))
|
print("Warning: subsampling X, as it has more samples then {}. X.shape={!s}".format(int(num_samples), X.shape))
|
||||||
if labels is not None:
|
if labels is not None:
|
||||||
subsample = []
|
subsample = []
|
||||||
for _, _, _, _, index, _ in scatter_label_generator(labels, X, (0, None, None)):
|
for _, _, _, _, index, _ in scatter_label_generator(labels, X, (0, None, None)):
|
||||||
|
|
@ -289,7 +289,10 @@ def get_x_y_var(model):
|
||||||
X = model.X.mean.values
|
X = model.X.mean.values
|
||||||
X_variance = model.X.variance.values
|
X_variance = model.X.variance.values
|
||||||
else:
|
else:
|
||||||
X = model.X.values
|
try:
|
||||||
|
X = model.X.values
|
||||||
|
except AttributeError:
|
||||||
|
X = model.X
|
||||||
X_variance = None
|
X_variance = None
|
||||||
try:
|
try:
|
||||||
Y = model.Y.values
|
Y = model.Y.values
|
||||||
|
|
@ -352,7 +355,7 @@ def x_frame1D(X,plot_limits=None,resolution=None):
|
||||||
xmin,xmax = X.min(0),X.max(0)
|
xmin,xmax = X.min(0),X.max(0)
|
||||||
xmin, xmax = xmin-0.25*(xmax-xmin), xmax+0.25*(xmax-xmin)
|
xmin, xmax = xmin-0.25*(xmax-xmin), xmax+0.25*(xmax-xmin)
|
||||||
elif len(plot_limits) == 2:
|
elif len(plot_limits) == 2:
|
||||||
xmin, xmax = plot_limits
|
xmin, xmax = map(np.atleast_1d, plot_limits)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Bad limits for plotting")
|
raise ValueError("Bad limits for plotting")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,4 +18,4 @@
|
||||||
|
|
||||||
|
|
||||||
from .util import align_subplot_array, align_subplots, fewerXticks, removeRightTicks, removeUpperTicks
|
from .util import align_subplot_array, align_subplots, fewerXticks, removeRightTicks, removeUpperTicks
|
||||||
from . import controllers
|
from . import controllers, base_plots
|
||||||
265
GPy/plotting/matplot_dep/base_plots.py
Normal file
265
GPy/plotting/matplot_dep/base_plots.py
Normal file
|
|
@ -0,0 +1,265 @@
|
||||||
|
# #Copyright (c) 2012, GPy authors (see AUTHORS.txt).
|
||||||
|
# Licensed under the BSD 3-clause license (see LICENSE.txt)
|
||||||
|
from matplotlib import pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
def ax_default(fignum, ax):
|
||||||
|
if ax is None:
|
||||||
|
fig = plt.figure(fignum)
|
||||||
|
ax = fig.add_subplot(111)
|
||||||
|
else:
|
||||||
|
fig = ax.figure
|
||||||
|
return fig, ax
|
||||||
|
|
||||||
|
def meanplot(x, mu, color='#3300FF', ax=None, fignum=None, linewidth=2,**kw):
|
||||||
|
_, axes = ax_default(fignum, ax)
|
||||||
|
return axes.plot(x,mu,color=color,linewidth=linewidth,**kw)
|
||||||
|
|
||||||
|
def gpplot(x, mu, lower, upper, edgecol='#3300FF', fillcol='#33CCFF', ax=None, fignum=None, **kwargs):
|
||||||
|
_, axes = ax_default(fignum, ax)
|
||||||
|
|
||||||
|
mu = mu.flatten()
|
||||||
|
x = x.flatten()
|
||||||
|
lower = lower.flatten()
|
||||||
|
upper = upper.flatten()
|
||||||
|
|
||||||
|
plots = []
|
||||||
|
|
||||||
|
#here's the mean
|
||||||
|
plots.append(meanplot(x, mu, edgecol, axes))
|
||||||
|
|
||||||
|
#here's the box
|
||||||
|
kwargs['linewidth']=0.5
|
||||||
|
if not 'alpha' in kwargs.keys():
|
||||||
|
kwargs['alpha'] = 0.3
|
||||||
|
plots.append(axes.fill(np.hstack((x,x[::-1])),np.hstack((upper,lower[::-1])),color=fillcol,**kwargs))
|
||||||
|
|
||||||
|
#this is the edge:
|
||||||
|
plots.append(meanplot(x, upper,color=edgecol, linewidth=0.2, ax=axes))
|
||||||
|
plots.append(meanplot(x, lower,color=edgecol, linewidth=0.2, ax=axes))
|
||||||
|
|
||||||
|
return plots
|
||||||
|
|
||||||
|
def gradient_fill(x, percentiles, ax=None, fignum=None, **kwargs):
|
||||||
|
_, ax = ax_default(fignum, ax)
|
||||||
|
|
||||||
|
plots = []
|
||||||
|
|
||||||
|
#here's the box
|
||||||
|
if 'linewidth' not in kwargs:
|
||||||
|
kwargs['linewidth'] = 0.5
|
||||||
|
if not 'alpha' in kwargs.keys():
|
||||||
|
kwargs['alpha'] = 1./(len(percentiles))
|
||||||
|
|
||||||
|
# pop where from kwargs
|
||||||
|
where = kwargs.pop('where') if 'where' in kwargs else None
|
||||||
|
# pop interpolate, which we actually do not do here!
|
||||||
|
if 'interpolate' in kwargs: kwargs.pop('interpolate')
|
||||||
|
|
||||||
|
def pairwise(inlist):
|
||||||
|
l = len(inlist)
|
||||||
|
for i in range(int(np.ceil(l/2.))):
|
||||||
|
yield inlist[:][i], inlist[:][(l-1)-i]
|
||||||
|
|
||||||
|
polycol = []
|
||||||
|
for y1, y2 in pairwise(percentiles):
|
||||||
|
import matplotlib.mlab as mlab
|
||||||
|
# Handle united data, such as dates
|
||||||
|
ax._process_unit_info(xdata=x, ydata=y1)
|
||||||
|
ax._process_unit_info(ydata=y2)
|
||||||
|
|
||||||
|
# Convert the arrays so we can work with them
|
||||||
|
from numpy import ma
|
||||||
|
x = ma.masked_invalid(ax.convert_xunits(x))
|
||||||
|
y1 = ma.masked_invalid(ax.convert_yunits(y1))
|
||||||
|
y2 = ma.masked_invalid(ax.convert_yunits(y2))
|
||||||
|
|
||||||
|
if y1.ndim == 0:
|
||||||
|
y1 = np.ones_like(x) * y1
|
||||||
|
if y2.ndim == 0:
|
||||||
|
y2 = np.ones_like(x) * y2
|
||||||
|
|
||||||
|
if where is None:
|
||||||
|
where = np.ones(len(x), np.bool)
|
||||||
|
else:
|
||||||
|
where = np.asarray(where, np.bool)
|
||||||
|
|
||||||
|
if not (x.shape == y1.shape == y2.shape == where.shape):
|
||||||
|
raise ValueError("Argument dimensions are incompatible")
|
||||||
|
|
||||||
|
mask = reduce(ma.mask_or, [ma.getmask(a) for a in (x, y1, y2)])
|
||||||
|
if mask is not ma.nomask:
|
||||||
|
where &= ~mask
|
||||||
|
|
||||||
|
polys = []
|
||||||
|
for ind0, ind1 in mlab.contiguous_regions(where):
|
||||||
|
xslice = x[ind0:ind1]
|
||||||
|
y1slice = y1[ind0:ind1]
|
||||||
|
y2slice = y2[ind0:ind1]
|
||||||
|
|
||||||
|
if not len(xslice):
|
||||||
|
continue
|
||||||
|
|
||||||
|
N = len(xslice)
|
||||||
|
X = np.zeros((2 * N + 2, 2), np.float)
|
||||||
|
|
||||||
|
# the purpose of the next two lines is for when y2 is a
|
||||||
|
# scalar like 0 and we want the fill to go all the way
|
||||||
|
# down to 0 even if none of the y1 sample points do
|
||||||
|
start = xslice[0], y2slice[0]
|
||||||
|
end = xslice[-1], y2slice[-1]
|
||||||
|
|
||||||
|
X[0] = start
|
||||||
|
X[N + 1] = end
|
||||||
|
|
||||||
|
X[1:N + 1, 0] = xslice
|
||||||
|
X[1:N + 1, 1] = y1slice
|
||||||
|
X[N + 2:, 0] = xslice[::-1]
|
||||||
|
X[N + 2:, 1] = y2slice[::-1]
|
||||||
|
|
||||||
|
polys.append(X)
|
||||||
|
polycol.extend(polys)
|
||||||
|
from matplotlib.collections import PolyCollection
|
||||||
|
plots.append(PolyCollection(polycol, **kwargs))
|
||||||
|
ax.add_collection(plots[-1], autolim=True)
|
||||||
|
ax.autoscale_view()
|
||||||
|
return plots
|
||||||
|
|
||||||
|
def gperrors(x, mu, lower, upper, edgecol=None, ax=None, fignum=None, **kwargs):
|
||||||
|
_, axes = ax_default(fignum, ax)
|
||||||
|
|
||||||
|
mu = mu.flatten()
|
||||||
|
x = x.flatten()
|
||||||
|
lower = lower.flatten()
|
||||||
|
upper = upper.flatten()
|
||||||
|
|
||||||
|
plots = []
|
||||||
|
|
||||||
|
if edgecol is None:
|
||||||
|
edgecol='#3300FF'
|
||||||
|
|
||||||
|
if not 'alpha' in kwargs.keys():
|
||||||
|
kwargs['alpha'] = 1.
|
||||||
|
|
||||||
|
|
||||||
|
if not 'lw' in kwargs.keys():
|
||||||
|
kwargs['lw'] = 1.
|
||||||
|
|
||||||
|
|
||||||
|
plots.append(axes.errorbar(x,mu,yerr=np.vstack([mu-lower,upper-mu]),color=edgecol,**kwargs))
|
||||||
|
plots[-1][0].remove()
|
||||||
|
return plots
|
||||||
|
|
||||||
|
|
||||||
|
def removeRightTicks(ax=None):
|
||||||
|
ax = ax or plt.gca()
|
||||||
|
for i, line in enumerate(ax.get_yticklines()):
|
||||||
|
if i%2 == 1: # odd indices
|
||||||
|
line.set_visible(False)
|
||||||
|
|
||||||
|
def removeUpperTicks(ax=None):
|
||||||
|
ax = ax or plt.gca()
|
||||||
|
for i, line in enumerate(ax.get_xticklines()):
|
||||||
|
if i%2 == 1: # odd indices
|
||||||
|
line.set_visible(False)
|
||||||
|
|
||||||
|
def fewerXticks(ax=None,divideby=2):
|
||||||
|
ax = ax or plt.gca()
|
||||||
|
ax.set_xticks(ax.get_xticks()[::divideby])
|
||||||
|
|
||||||
|
def align_subplots(N,M,xlim=None, ylim=None):
|
||||||
|
"""make all of the subplots have the same limits, turn off unnecessary ticks"""
|
||||||
|
#find sensible xlim,ylim
|
||||||
|
if xlim is None:
|
||||||
|
xlim = [np.inf,-np.inf]
|
||||||
|
for i in range(N*M):
|
||||||
|
plt.subplot(N,M,i+1)
|
||||||
|
xlim[0] = min(xlim[0],plt.xlim()[0])
|
||||||
|
xlim[1] = max(xlim[1],plt.xlim()[1])
|
||||||
|
if ylim is None:
|
||||||
|
ylim = [np.inf,-np.inf]
|
||||||
|
for i in range(N*M):
|
||||||
|
plt.subplot(N,M,i+1)
|
||||||
|
ylim[0] = min(ylim[0],plt.ylim()[0])
|
||||||
|
ylim[1] = max(ylim[1],plt.ylim()[1])
|
||||||
|
|
||||||
|
for i in range(N*M):
|
||||||
|
plt.subplot(N,M,i+1)
|
||||||
|
plt.xlim(xlim)
|
||||||
|
plt.ylim(ylim)
|
||||||
|
if (i)%M:
|
||||||
|
plt.yticks([])
|
||||||
|
else:
|
||||||
|
removeRightTicks()
|
||||||
|
if i<(M*(N-1)):
|
||||||
|
plt.xticks([])
|
||||||
|
else:
|
||||||
|
removeUpperTicks()
|
||||||
|
|
||||||
|
def align_subplot_array(axes,xlim=None, ylim=None):
|
||||||
|
"""
|
||||||
|
Make all of the axes in the array hae the same limits, turn off unnecessary ticks
|
||||||
|
use plt.subplots() to get an array of axes
|
||||||
|
"""
|
||||||
|
#find sensible xlim,ylim
|
||||||
|
if xlim is None:
|
||||||
|
xlim = [np.inf,-np.inf]
|
||||||
|
for ax in axes.flatten():
|
||||||
|
xlim[0] = min(xlim[0],ax.get_xlim()[0])
|
||||||
|
xlim[1] = max(xlim[1],ax.get_xlim()[1])
|
||||||
|
if ylim is None:
|
||||||
|
ylim = [np.inf,-np.inf]
|
||||||
|
for ax in axes.flatten():
|
||||||
|
ylim[0] = min(ylim[0],ax.get_ylim()[0])
|
||||||
|
ylim[1] = max(ylim[1],ax.get_ylim()[1])
|
||||||
|
|
||||||
|
N,M = axes.shape
|
||||||
|
for i,ax in enumerate(axes.flatten()):
|
||||||
|
ax.set_xlim(xlim)
|
||||||
|
ax.set_ylim(ylim)
|
||||||
|
if (i)%M:
|
||||||
|
ax.set_yticks([])
|
||||||
|
else:
|
||||||
|
removeRightTicks(ax)
|
||||||
|
if i<(M*(N-1)):
|
||||||
|
ax.set_xticks([])
|
||||||
|
else:
|
||||||
|
removeUpperTicks(ax)
|
||||||
|
|
||||||
|
def x_frame1D(X,plot_limits=None,resolution=None):
|
||||||
|
"""
|
||||||
|
Internal helper function for making plots, returns a set of input values to plot as well as lower and upper limits
|
||||||
|
"""
|
||||||
|
assert X.shape[1] ==1, "x_frame1D is defined for one-dimensional inputs"
|
||||||
|
if plot_limits is None:
|
||||||
|
from ...core.parameterization.variational import VariationalPosterior
|
||||||
|
if isinstance(X, VariationalPosterior):
|
||||||
|
xmin,xmax = X.mean.min(0),X.mean.max(0)
|
||||||
|
else:
|
||||||
|
xmin,xmax = X.min(0),X.max(0)
|
||||||
|
xmin, xmax = xmin-0.2*(xmax-xmin), xmax+0.2*(xmax-xmin)
|
||||||
|
elif len(plot_limits)==2:
|
||||||
|
xmin, xmax = plot_limits
|
||||||
|
else:
|
||||||
|
raise ValueError("Bad limits for plotting")
|
||||||
|
|
||||||
|
Xnew = np.linspace(xmin,xmax,resolution or 200)[:,None]
|
||||||
|
return Xnew, xmin, xmax
|
||||||
|
|
||||||
|
def x_frame2D(X,plot_limits=None,resolution=None):
|
||||||
|
"""
|
||||||
|
Internal helper function for making plots, returns a set of input values to plot as well as lower and upper limits
|
||||||
|
"""
|
||||||
|
assert X.shape[1] ==2, "x_frame2D is defined for two-dimensional inputs"
|
||||||
|
if plot_limits is None:
|
||||||
|
xmin,xmax = X.min(0),X.max(0)
|
||||||
|
xmin, xmax = xmin-0.2*(xmax-xmin), xmax+0.2*(xmax-xmin)
|
||||||
|
elif len(plot_limits)==2:
|
||||||
|
xmin, xmax = plot_limits
|
||||||
|
else:
|
||||||
|
raise ValueError("Bad limits for plotting")
|
||||||
|
|
||||||
|
resolution = resolution or 50
|
||||||
|
xx,yy = np.mgrid[xmin[0]:xmax[0]:1j*resolution,xmin[1]:xmax[1]:1j*resolution]
|
||||||
|
Xnew = np.vstack((xx.flatten(),yy.flatten())).T
|
||||||
|
return Xnew, xx, yy, xmin, xmax
|
||||||
|
|
@ -42,13 +42,14 @@ class MatplotlibPlots(AbstractPlottingLibrary):
|
||||||
super(MatplotlibPlots, self).__init__()
|
super(MatplotlibPlots, self).__init__()
|
||||||
self._defaults = defaults.__dict__
|
self._defaults = defaults.__dict__
|
||||||
|
|
||||||
def figure(self, rows=1, cols=1, **kwargs):
|
def figure(self, rows=1, cols=1, gridspec_kwargs={}, tight_layout=True, **kwargs):
|
||||||
fig = plt.figure(**kwargs)
|
fig = plt.figure(tight_layout=tight_layout, **kwargs)
|
||||||
fig.rows = rows
|
fig.rows = rows
|
||||||
fig.cols = cols
|
fig.cols = cols
|
||||||
|
fig.gridspec = plt.GridSpec(rows, cols, **gridspec_kwargs)
|
||||||
return fig
|
return fig
|
||||||
|
|
||||||
def new_canvas(self, figure=None, col=1, row=1, projection='2d', xlabel=None, ylabel=None, zlabel=None, title=None, xlim=None, ylim=None, zlim=None, **kwargs):
|
def new_canvas(self, figure=None, row=1, col=1, projection='2d', xlabel=None, ylabel=None, zlabel=None, title=None, xlim=None, ylim=None, zlim=None, **kwargs):
|
||||||
if projection == '3d':
|
if projection == '3d':
|
||||||
from mpl_toolkits.mplot3d import Axes3D
|
from mpl_toolkits.mplot3d import Axes3D
|
||||||
elif projection == '2d':
|
elif projection == '2d':
|
||||||
|
|
@ -56,7 +57,9 @@ class MatplotlibPlots(AbstractPlottingLibrary):
|
||||||
if 'ax' in kwargs:
|
if 'ax' in kwargs:
|
||||||
ax = kwargs.pop('ax')
|
ax = kwargs.pop('ax')
|
||||||
else:
|
else:
|
||||||
if 'num' in kwargs and 'figsize' in kwargs:
|
if figure is not None:
|
||||||
|
fig = figure
|
||||||
|
elif 'num' in kwargs and 'figsize' in kwargs:
|
||||||
fig = self.figure(num=kwargs.pop('num'), figsize=kwargs.pop('figsize'))
|
fig = self.figure(num=kwargs.pop('num'), figsize=kwargs.pop('figsize'))
|
||||||
elif 'num' in kwargs:
|
elif 'num' in kwargs:
|
||||||
fig = self.figure(num=kwargs.pop('num'))
|
fig = self.figure(num=kwargs.pop('num'))
|
||||||
|
|
@ -66,7 +69,7 @@ class MatplotlibPlots(AbstractPlottingLibrary):
|
||||||
fig = self.figure()
|
fig = self.figure()
|
||||||
|
|
||||||
#if hasattr(fig, 'rows') and hasattr(fig, 'cols'):
|
#if hasattr(fig, 'rows') and hasattr(fig, 'cols'):
|
||||||
ax = fig.add_subplot(fig.rows, fig.cols, (col,row), projection=projection)
|
ax = fig.add_subplot(fig.gridspec[row-1, col-1], projection=projection)
|
||||||
|
|
||||||
if xlim is not None: ax.set_xlim(xlim)
|
if xlim is not None: ax.set_xlim(xlim)
|
||||||
if ylim is not None: ax.set_ylim(ylim)
|
if ylim is not None: ax.set_ylim(ylim)
|
||||||
|
|
@ -79,7 +82,7 @@ class MatplotlibPlots(AbstractPlottingLibrary):
|
||||||
return ax, kwargs
|
return ax, kwargs
|
||||||
|
|
||||||
def add_to_canvas(self, ax, plots, legend=False, title=None, **kwargs):
|
def add_to_canvas(self, ax, plots, legend=False, title=None, **kwargs):
|
||||||
ax.autoscale_view()
|
#ax.autoscale_view()
|
||||||
fontdict=dict(family='sans-serif', weight='light', size=9)
|
fontdict=dict(family='sans-serif', weight='light', size=9)
|
||||||
if legend is True:
|
if legend is True:
|
||||||
ax.legend(*ax.get_legend_handles_labels())
|
ax.legend(*ax.get_legend_handles_labels())
|
||||||
|
|
@ -89,9 +92,7 @@ class MatplotlibPlots(AbstractPlottingLibrary):
|
||||||
if title is not None: ax.figure.suptitle(title)
|
if title is not None: ax.figure.suptitle(title)
|
||||||
return ax
|
return ax
|
||||||
|
|
||||||
def show_canvas(self, ax, tight_layout=False, **kwargs):
|
def show_canvas(self, ax):
|
||||||
if tight_layout:
|
|
||||||
ax.figure.tight_layout()
|
|
||||||
ax.figure.canvas.draw()
|
ax.figure.canvas.draw()
|
||||||
return ax.figure
|
return ax.figure
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,5 +72,5 @@ ard = dict(linewidth=1.2, barmode='stack')
|
||||||
latent = dict(colorscale='Greys', reversescale=True, zsmooth='best')
|
latent = dict(colorscale='Greys', reversescale=True, zsmooth='best')
|
||||||
gradient = dict(colorscale='RdBu', opacity=.7)
|
gradient = dict(colorscale='RdBu', opacity=.7)
|
||||||
magnification = dict(colorscale='Greys', zsmooth='best', reversescale=True)
|
magnification = dict(colorscale='Greys', zsmooth='best', reversescale=True)
|
||||||
latent_scatter = dict(marker_kwargs=dict(size='15', opacity=.7))
|
latent_scatter = dict(marker_kwargs=dict(size='5', opacity=.7))
|
||||||
# annotation = dict(fontdict=dict(family='sans-serif', weight='light', fontsize=9), zorder=.3, alpha=.7)
|
# annotation = dict(fontdict=dict(family='sans-serif', weight='light', fontsize=9), zorder=.3, alpha=.7)
|
||||||
|
|
@ -130,11 +130,12 @@ class PlotlyPlots(AbstractPlottingLibrary):
|
||||||
except:
|
except:
|
||||||
#not matplotlib marker
|
#not matplotlib marker
|
||||||
pass
|
pass
|
||||||
|
marker_kwargs = marker_kwargs or {}
|
||||||
marker_kwargs.setdefault('symbol', marker)
|
marker_kwargs.setdefault('symbol', marker)
|
||||||
if Z is not None:
|
if Z is not None:
|
||||||
return Scatter3d(x=X, y=Y, z=Z, mode='markers',
|
return Scatter3d(x=X, y=Y, z=Z, mode='markers',
|
||||||
showlegend=label is not None,
|
showlegend=label is not None,
|
||||||
marker=Marker(color=color, colorscale=cmap, **marker_kwargs or {}),
|
marker=Marker(color=color, colorscale=cmap, **marker_kwargs),
|
||||||
name=label, **kwargs)
|
name=label, **kwargs)
|
||||||
return Scatter(x=X, y=Y, mode='markers', showlegend=label is not None,
|
return Scatter(x=X, y=Y, mode='markers', showlegend=label is not None,
|
||||||
marker=Marker(color=color, colorscale=cmap, **marker_kwargs or {}),
|
marker=Marker(color=color, colorscale=cmap, **marker_kwargs or {}),
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,9 @@
|
||||||
# Copyright (c) 2014, Max Zwiessele
|
# Copyright (c) 2014, Max Zwiessele, GPy Authors
|
||||||
# Licensed under the BSD 3-clause license (see LICENSE.txt)
|
# Licensed under the BSD 3-clause license (see LICENSE.txt)
|
||||||
"""
|
|
||||||
|
|
||||||
MaxZ
|
|
||||||
|
|
||||||
"""
|
|
||||||
import unittest
|
import unittest
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
def deepTest(reason):
|
def deepTest(reason):
|
||||||
if reason:
|
if reason:
|
||||||
return lambda x:x
|
return lambda x:x
|
||||||
return unittest.skip("Not deep scanning, enable deepscan by adding 'deep' argument")
|
return unittest.skip("Not deep scanning, enable deepscan by adding 'deep' argument to unittest call")
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 9 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 9 KiB |
|
|
@ -51,5 +51,20 @@ class InferenceXTestCase(unittest.TestCase):
|
||||||
np.testing.assert_array_almost_equal(m.X, mi.X, decimal=2)
|
np.testing.assert_array_almost_equal(m.X, mi.X, decimal=2)
|
||||||
|
|
||||||
|
|
||||||
|
class HMCSamplerTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_sampling(self):
|
||||||
|
np.random.seed(1)
|
||||||
|
x = np.linspace(0.,2*np.pi,100)[:,None]
|
||||||
|
y = -np.cos(x)+np.random.randn(*x.shape)*0.3+1
|
||||||
|
|
||||||
|
m = GPy.models.GPRegression(x,y)
|
||||||
|
m.kern.lengthscale.set_prior(GPy.priors.Gamma.from_EV(1.,10.))
|
||||||
|
m.kern.variance.set_prior(GPy.priors.Gamma.from_EV(1.,10.))
|
||||||
|
m.likelihood.variance.set_prior(GPy.priors.Gamma.from_EV(1.,10.))
|
||||||
|
|
||||||
|
hmc = GPy.inference.mcmc.HMC(m,stepsize=1e-2)
|
||||||
|
s = hmc.sample(num_samples=3)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,9 @@ class Kern_check_model(GPy.core.Model):
|
||||||
X = np.random.randn(20, kernel.input_dim)
|
X = np.random.randn(20, kernel.input_dim)
|
||||||
if dL_dK is None:
|
if dL_dK is None:
|
||||||
if X2 is None:
|
if X2 is None:
|
||||||
dL_dK = np.ones((X.shape[0], X.shape[0]))
|
dL_dK = np.random.rand(X.shape[0], X.shape[0])
|
||||||
else:
|
else:
|
||||||
dL_dK = np.ones((X.shape[0], X2.shape[0]))
|
dL_dK = np.random.rand(X.shape[0], X2.shape[0])
|
||||||
|
|
||||||
self.kernel = kernel
|
self.kernel = kernel
|
||||||
self.X = X
|
self.X = X
|
||||||
|
|
@ -310,7 +310,7 @@ class KernelGradientTestsContinuous(unittest.TestCase):
|
||||||
self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose))
|
self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose))
|
||||||
|
|
||||||
def test_RBF(self):
|
def test_RBF(self):
|
||||||
k = GPy.kern.RBF(self.D)
|
k = GPy.kern.RBF(self.D, ARD=True)
|
||||||
k.randomize()
|
k.randomize()
|
||||||
self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose))
|
self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose))
|
||||||
|
|
||||||
|
|
@ -324,6 +324,11 @@ class KernelGradientTestsContinuous(unittest.TestCase):
|
||||||
k.randomize()
|
k.randomize()
|
||||||
self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose))
|
self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose))
|
||||||
|
|
||||||
|
def test_Poly(self):
|
||||||
|
k = GPy.kern.Poly(self.D, order=5)
|
||||||
|
k.randomize()
|
||||||
|
self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose))
|
||||||
|
|
||||||
def test_standard_periodic(self):
|
def test_standard_periodic(self):
|
||||||
k = GPy.kern.StdPeriodic(self.D, self.D-1)
|
k = GPy.kern.StdPeriodic(self.D, self.D-1)
|
||||||
k.randomize()
|
k.randomize()
|
||||||
|
|
@ -366,6 +371,7 @@ class KernelTestsNonContinuous(unittest.TestCase):
|
||||||
self.X2[:(N0*2), -1] = 0
|
self.X2[:(N0*2), -1] = 0
|
||||||
self.X2[(N0*2):, -1] = 1
|
self.X2[(N0*2):, -1] = 1
|
||||||
|
|
||||||
|
@unittest.expectedFailure
|
||||||
def test_IndependentOutputs(self):
|
def test_IndependentOutputs(self):
|
||||||
k = GPy.kern.RBF(self.D, active_dims=range(self.D))
|
k = GPy.kern.RBF(self.D, active_dims=range(self.D))
|
||||||
kern = GPy.kern.IndependentOutputs(k, -1, 'ind_single')
|
kern = GPy.kern.IndependentOutputs(k, -1, 'ind_single')
|
||||||
|
|
@ -374,6 +380,7 @@ class KernelTestsNonContinuous(unittest.TestCase):
|
||||||
kern = GPy.kern.IndependentOutputs(k, -1, name='ind_split')
|
kern = GPy.kern.IndependentOutputs(k, -1, name='ind_split')
|
||||||
self.assertTrue(check_kernel_gradient_functions(kern, X=self.X, X2=self.X2, verbose=verbose, fixed_X_dims=-1))
|
self.assertTrue(check_kernel_gradient_functions(kern, X=self.X, X2=self.X2, verbose=verbose, fixed_X_dims=-1))
|
||||||
|
|
||||||
|
@unittest.expectedFailure
|
||||||
def test_Hierarchical(self):
|
def test_Hierarchical(self):
|
||||||
k = [GPy.kern.RBF(2, active_dims=[0,2], name='rbf1'), GPy.kern.RBF(2, active_dims=[0,2], name='rbf2')]
|
k = [GPy.kern.RBF(2, active_dims=[0,2], name='rbf1'), GPy.kern.RBF(2, active_dims=[0,2], name='rbf2')]
|
||||||
kern = GPy.kern.IndependentOutputs(k, -1, name='ind_split')
|
kern = GPy.kern.IndependentOutputs(k, -1, name='ind_split')
|
||||||
|
|
@ -467,7 +474,7 @@ class Kernel_Psi_statistics_GradientTests(unittest.TestCase):
|
||||||
self.w1 = np.random.randn(N)
|
self.w1 = np.random.randn(N)
|
||||||
self.w2 = np.random.randn(N,M)
|
self.w2 = np.random.randn(N,M)
|
||||||
self.w3 = np.random.randn(M,M)
|
self.w3 = np.random.randn(M,M)
|
||||||
self.w3 = self.w3+self.w3.T
|
self.w3 = self.w3#+self.w3.T
|
||||||
self.w3n = np.random.randn(N,M,M)
|
self.w3n = np.random.randn(N,M,M)
|
||||||
self.w3n = self.w3n+np.swapaxes(self.w3n, 1,2)
|
self.w3n = self.w3n+np.swapaxes(self.w3n, 1,2)
|
||||||
|
|
||||||
|
|
@ -475,7 +482,7 @@ class Kernel_Psi_statistics_GradientTests(unittest.TestCase):
|
||||||
from GPy.kern import RBF,Linear,MLP,Bias,White
|
from GPy.kern import RBF,Linear,MLP,Bias,White
|
||||||
Q = self.Z.shape[1]
|
Q = self.Z.shape[1]
|
||||||
kernels = [RBF(Q,ARD=True), Linear(Q,ARD=True),MLP(Q,ARD=True), RBF(Q,ARD=True)+Linear(Q,ARD=True)+Bias(Q)+White(Q)
|
kernels = [RBF(Q,ARD=True), Linear(Q,ARD=True),MLP(Q,ARD=True), RBF(Q,ARD=True)+Linear(Q,ARD=True)+Bias(Q)+White(Q)
|
||||||
,RBF(Q,ARD=True)+Bias(Q)+White(Q), Linear(Q,ARD=True)+Bias(Q)+White(Q)]
|
,RBF(Q,ARD=True)+Bias(Q)+White(Q), Linear(Q,ARD=True)+Bias(Q)+White(Q)]
|
||||||
|
|
||||||
for k in kernels:
|
for k in kernels:
|
||||||
k.randomize()
|
k.randomize()
|
||||||
|
|
|
||||||
|
|
@ -27,16 +27,24 @@
|
||||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# SKIPPING PLOTTING BECAUSE IT BEHAVES DIFFERENTLY ON DIFFERENT
|
||||||
|
# SYSTEMS, AND WILL MISBEHAVE
|
||||||
|
from nose import SkipTest
|
||||||
|
raise SkipTest("Skipping Matplotlib testing")
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
import matplotlib
|
import matplotlib
|
||||||
from unittest.case import TestCase
|
from unittest.case import TestCase
|
||||||
matplotlib.use('agg')
|
matplotlib.use('agg')
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import GPy, os
|
import GPy, os
|
||||||
from nose import SkipTest
|
|
||||||
|
|
||||||
from ..util.config import config
|
from GPy.util.config import config
|
||||||
from ..plotting import change_plotting_library, plotting_library
|
from GPy.plotting import change_plotting_library, plotting_library
|
||||||
|
|
||||||
class ConfigTest(TestCase):
|
class ConfigTest(TestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
|
|
@ -69,8 +77,8 @@ def _image_directories():
|
||||||
#module_name = __init__.__module__
|
#module_name = __init__.__module__
|
||||||
#mods = module_name.split('.')
|
#mods = module_name.split('.')
|
||||||
#basedir = os.path.join(*mods)
|
#basedir = os.path.join(*mods)
|
||||||
result_dir = os.path.join(basedir, 'testresult')
|
result_dir = os.path.join(basedir, 'testresult','.')
|
||||||
baseline_dir = os.path.join(basedir, 'baseline')
|
baseline_dir = os.path.join(basedir, 'baseline','.')
|
||||||
if not os.path.exists(result_dir):
|
if not os.path.exists(result_dir):
|
||||||
cbook.mkdirs(result_dir)
|
cbook.mkdirs(result_dir)
|
||||||
return baseline_dir, result_dir
|
return baseline_dir, result_dir
|
||||||
|
|
|
||||||
|
|
@ -305,6 +305,11 @@ class acclaim_skeleton(skeleton):
|
||||||
fid.close()
|
fid.close()
|
||||||
return channels
|
return channels
|
||||||
|
|
||||||
|
def save_channels(self, file_name, channels):
|
||||||
|
with open(file_name,'w') as fid:
|
||||||
|
self.writ_channels(fid, channels)
|
||||||
|
fid.close()
|
||||||
|
|
||||||
def load_skel(self, file_name):
|
def load_skel(self, file_name):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
@ -469,6 +474,18 @@ class acclaim_skeleton(skeleton):
|
||||||
self.smooth_angle_channels(channels)
|
self.smooth_angle_channels(channels)
|
||||||
return channels
|
return channels
|
||||||
|
|
||||||
|
def writ_channels(self, fid, channels):
|
||||||
|
fid.write('#!OML:ASF \n')
|
||||||
|
fid.write(':FULLY-SPECIFIED\n')
|
||||||
|
fid.write(':DEGREES\n')
|
||||||
|
num_frames = channels.shape[0]
|
||||||
|
for i_frame in range(num_frames):
|
||||||
|
fid.write(str(i_frame+1)+'\n')
|
||||||
|
offset = 0
|
||||||
|
for vertex in self.vertices:
|
||||||
|
fid.write(vertex.name+' '+ ' '.join([str(v) for v in channels[i_frame,offset:offset+len(vertex.meta['channels'])]])+'\n')
|
||||||
|
offset += len(vertex.meta['channels'])
|
||||||
|
|
||||||
|
|
||||||
def read_documentation(self, fid):
|
def read_documentation(self, fid):
|
||||||
"""Read documentation from an acclaim skeleton file stream."""
|
"""Read documentation from an acclaim skeleton file stream."""
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,14 @@ def divide_data(datanum, rank, size):
|
||||||
offset = size*rank+residue
|
offset = size*rank+residue
|
||||||
return offset, offset+size, datanum_list
|
return offset, offset+size, datanum_list
|
||||||
|
|
||||||
def optimize_parallel(model, optimizer=None, messages=True, max_iters=1000, outpath='.', interval=100, name=None):
|
def optimize_parallel(model, optimizer=None, messages=True, max_iters=1000, outpath='.', interval=100, name=None, **kwargs):
|
||||||
from math import ceil
|
from math import ceil
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import os
|
import os
|
||||||
if name is None: name = model.name
|
if name is None: name = model.name
|
||||||
stop = 0
|
stop = 0
|
||||||
for iter in range(int(ceil(float(max_iters)/interval))):
|
for iter in range(int(ceil(float(max_iters)/interval))):
|
||||||
model.optimize(optimizer=optimizer, messages= True if messages and model.mpi_comm.rank==model.mpi_root else False, max_iters=interval)
|
model.optimize(optimizer=optimizer, messages= True if messages and model.mpi_comm.rank==model.mpi_root else False, max_iters=interval, **kwargs)
|
||||||
if model.mpi_comm.rank==model.mpi_root:
|
if model.mpi_comm.rank==model.mpi_root:
|
||||||
timenow = datetime.now()
|
timenow = datetime.now()
|
||||||
timestr = timenow.strftime('%Y:%m:%d_%H:%M:%S')
|
timestr = timenow.strftime('%Y:%m:%d_%H:%M:%S')
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,32 @@ import shlex
|
||||||
sys.path.insert(0, os.path.abspath('../../'))
|
sys.path.insert(0, os.path.abspath('../../'))
|
||||||
sys.path.insert(0, os.path.abspath('../../GPy/'))
|
sys.path.insert(0, os.path.abspath('../../GPy/'))
|
||||||
|
|
||||||
|
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
|
||||||
|
|
||||||
|
#on_rtd = True
|
||||||
|
if on_rtd:
|
||||||
|
# sys.path.append(os.path.abspath('../GPy'))
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
proc = subprocess.Popen("pwd", stdout=subprocess.PIPE, shell=True)
|
||||||
|
(out, err) = proc.communicate()
|
||||||
|
print "program output:", out
|
||||||
|
proc = subprocess.Popen("ls ../../", stdout=subprocess.PIPE, shell=True)
|
||||||
|
(out, err) = proc.communicate()
|
||||||
|
print "program output:", out
|
||||||
|
#Lets regenerate our rst files from the source, -P adds private modules (i.e kern._src)
|
||||||
|
proc = subprocess.Popen("sphinx-apidoc -P -f -o . ../../GPy", stdout=subprocess.PIPE, shell=True)
|
||||||
|
(out, err) = proc.communicate()
|
||||||
|
print "program output:", out
|
||||||
|
#proc = subprocess.Popen("whereis numpy", stdout=subprocess.PIPE, shell=True)
|
||||||
|
#(out, err) = proc.communicate()
|
||||||
|
#print "program output:", out
|
||||||
|
#proc = subprocess.Popen("whereis matplotlib", stdout=subprocess.PIPE, shell=True)
|
||||||
|
#(out, err) = proc.communicate()
|
||||||
|
#print "program output:", out
|
||||||
|
|
||||||
|
|
||||||
# -- General configuration ------------------------------------------------
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
.. GPy documentation master file, created by
|
|
||||||
sphinx-quickstart on Fri Sep 18 18:16:28 2015.
|
|
||||||
You can adapt this file completely to your liking, but it should at least
|
|
||||||
contain the root `toctree` directive.
|
|
||||||
|
|
||||||
Welcome to GPy's documentation!
|
|
||||||
===============================
|
|
||||||
|
|
||||||
Contents:
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Indices and tables
|
|
||||||
==================
|
|
||||||
|
|
||||||
* :ref:`genindex`
|
|
||||||
* :ref:`modindex`
|
|
||||||
* :ref:`search`
|
|
||||||
|
|
||||||
1
doc/source/requirements.txt
Normal file
1
doc/source/requirements.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
paramz
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.9.4
|
current_version = 0.9.7
|
||||||
tag = True
|
tag = True
|
||||||
commit = True
|
commit = True
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue