From e18de2b2c001b8860bb86c883780a4ce70aebe18 Mon Sep 17 00:00:00 2001 From: Zhenwen Dai Date: Thu, 22 Oct 2015 17:09:22 +0100 Subject: [PATCH 01/40] resolve the requirement of dL_dpsi2 to be symmetric --- GPy/kern/src/add.py | 17 +++++++++++------ GPy/kern/src/psi_comp/rbf_psi_comp.py | 2 ++ GPy/kern/src/psi_comp/rbf_psi_gpucomp.py | 4 ++++ GPy/testing/kernel_tests.py | 4 ++-- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/GPy/kern/src/add.py b/GPy/kern/src/add.py index 9f80ac9d..06bb4870 100644 --- a/GPy/kern/src/add.py +++ b/GPy/kern/src/add.py @@ -181,6 +181,8 @@ class Add(CombinationKernel): return psi2 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) from .static import White, Bias for p1 in self.parts: @@ -192,12 +194,13 @@ class Add(CombinationKernel): if isinstance(p2, White): continue 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 - 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) 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) from .static import White, Bias target = np.zeros(Z.shape) @@ -210,13 +213,15 @@ class Add(CombinationKernel): if isinstance(p2, White): continue elif isinstance(p2, Bias): - eff_dL_dpsi1 += dL_dpsi2.sum(1) * p2.variance * 2. + eff_dL_dpsi1 += tmp * p2.variance 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) return target 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) from .static import White, Bias target_grads = [np.zeros(v.shape) for v in variational_posterior.parameters] @@ -229,9 +234,9 @@ class Add(CombinationKernel): if isinstance(p2, White): continue elif isinstance(p2, Bias): - eff_dL_dpsi1 += dL_dpsi2.sum(1) * p2.variance * 2. + eff_dL_dpsi1 += tmp * p2.variance 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) [np.add(target_grads[i],grads[i],target_grads[i]) for i in range(len(grads))] return target_grads diff --git a/GPy/kern/src/psi_comp/rbf_psi_comp.py b/GPy/kern/src/psi_comp/rbf_psi_comp.py index 5667eec6..6e6c1957 100644 --- a/GPy/kern/src/psi_comp/rbf_psi_comp.py +++ b/GPy/kern/src/psi_comp/rbf_psi_comp.py @@ -106,6 +106,8 @@ def _psi2compDer(dL_dpsi2, variance, lengthscale, Z, mu, S): denom = 1./(2*S+lengthscale2) 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 Lpsi2 = dL_dpsi2*_psi2 # dL_dpsi2 is MxM, using broadcast to multiply N out Lpsi2sum = Lpsi2.reshape(N,M*M).sum(1) #N diff --git a/GPy/kern/src/psi_comp/rbf_psi_gpucomp.py b/GPy/kern/src/psi_comp/rbf_psi_gpucomp.py index 50945db6..30312d68 100644 --- a/GPy/kern/src/psi_comp/rbf_psi_gpucomp.py +++ b/GPy/kern/src/psi_comp/rbf_psi_gpucomp.py @@ -370,6 +370,10 @@ class PSICOMP_RBF_GPU(PSICOMP_RBF): @Cache_this(limit=10, ignore_args=(0,2,3,4)) 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 from ....util.linalg_gpu import sum_axis ARD = (len(lengthscale)!=1) diff --git a/GPy/testing/kernel_tests.py b/GPy/testing/kernel_tests.py index e81ce2cf..e2f4324a 100644 --- a/GPy/testing/kernel_tests.py +++ b/GPy/testing/kernel_tests.py @@ -468,7 +468,7 @@ class Kernel_Psi_statistics_GradientTests(unittest.TestCase): self.w1 = np.random.randn(N) self.w2 = np.random.randn(N,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 = self.w3n+np.swapaxes(self.w3n, 1,2) @@ -476,7 +476,7 @@ class Kernel_Psi_statistics_GradientTests(unittest.TestCase): from GPy.kern import RBF,Linear,MLP,Bias,White 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) - ,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: k.randomize() From ee5a562c67a850740207cfcc52cffd01afc35c78 Mon Sep 17 00:00:00 2001 From: Zhenwen Dai Date: Thu, 22 Oct 2015 17:57:03 +0100 Subject: [PATCH 02/40] fix the dL_dK symmetric issue for linear kernel and set dL_dK in the kernel test to be random. --- GPy/kern/src/linear.py | 13 +++++++++---- GPy/testing/kernel_tests.py | 6 +++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/GPy/kern/src/linear.py b/GPy/kern/src/linear.py index 25f6299d..0c897c74 100644 --- a/GPy/kern/src/linear.py +++ b/GPy/kern/src/linear.py @@ -73,14 +73,15 @@ class Linear(Kern): return np.sum(self.variances * np.square(X), -1) 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 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.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: #product = X[:, None, :] * X2[None, :, :] #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: 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): + if X2 is None: dL_dK = (dL_dK+dL_dK.T)/2 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: #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): + if X2 is None: dL_dK = (dL_dK+dL_dK.T)/2 if X2 is None: return 2*np.ones(X.shape)*self.variances else: @@ -162,6 +165,7 @@ class LinearFull(Kern): 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): + 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.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) @@ -175,6 +179,7 @@ class LinearFull(Kern): 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): + if X2 is None: dL_dK = (dL_dK+dL_dK.T)/2 P = np.dot(self.W, self.W.T) + np.diag(self.kappa) if X2 is None: return 2.*np.einsum('ij,jk,kl->il', dL_dK, X, P) diff --git a/GPy/testing/kernel_tests.py b/GPy/testing/kernel_tests.py index e2f4324a..bbfb565b 100644 --- a/GPy/testing/kernel_tests.py +++ b/GPy/testing/kernel_tests.py @@ -32,9 +32,9 @@ class Kern_check_model(GPy.core.Model): X = np.random.randn(20, kernel.input_dim) if dL_dK 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: - 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.X = X @@ -311,7 +311,7 @@ class KernelGradientTestsContinuous(unittest.TestCase): self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose)) def test_RBF(self): - k = GPy.kern.RBF(self.D) + k = GPy.kern.RBF(self.D, ARD=True) k.randomize() self.assertTrue(check_kernel_gradient_functions(k, X=self.X, X2=self.X2, verbose=verbose)) From d377071e3a6e6458418ca68e362cb8caf10412f2 Mon Sep 17 00:00:00 2001 From: Zhenwen Dai Date: Tue, 27 Oct 2015 22:21:09 +0000 Subject: [PATCH 03/40] add save channel function to mocap lib --- GPy/util/mocap.py | 17 +++++++++++++++++ doc/source/index.rst~ | 22 ---------------------- 2 files changed, 17 insertions(+), 22 deletions(-) delete mode 100644 doc/source/index.rst~ diff --git a/GPy/util/mocap.py b/GPy/util/mocap.py index 4f6336c5..e405d3a1 100644 --- a/GPy/util/mocap.py +++ b/GPy/util/mocap.py @@ -304,6 +304,11 @@ class acclaim_skeleton(skeleton): channels = self.read_channels(fid) fid.close() 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): @@ -469,6 +474,18 @@ class acclaim_skeleton(skeleton): self.smooth_angle_channels(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): """Read documentation from an acclaim skeleton file stream.""" diff --git a/doc/source/index.rst~ b/doc/source/index.rst~ deleted file mode 100644 index 48ec0422..00000000 --- a/doc/source/index.rst~ +++ /dev/null @@ -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` - From 2bf1be5500a0b4825d16b5dc2f448448358ccee0 Mon Sep 17 00:00:00 2001 From: Zhenwen Dai Date: Mon, 2 Nov 2015 21:18:56 +0000 Subject: [PATCH 04/40] bug fix for lbfgs with max_iters big than 15000 --- GPy/inference/optimization/optimization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPy/inference/optimization/optimization.py b/GPy/inference/optimization/optimization.py index 1052e909..ceceb222 100644 --- a/GPy/inference/optimization/optimization.py +++ b/GPy/inference/optimization/optimization.py @@ -124,7 +124,7 @@ class opt_lbfgsb(Optimizer): opt_dict['factr'] = self.bfgs_factor opt_result = optimize.fmin_l_bfgs_b(f_fp, self.x_init, iprint=iprint, - maxfun=self.max_iters, **opt_dict) + maxfun=self.max_iters,maxiter=self.max_iters, **opt_dict) self.x_opt = opt_result[0] self.f_opt = f_fp(self.x_opt)[0] self.funct_eval = opt_result[2]['funcalls'] From 92248b62e632c3474f41d19612d12a1a4b3d36e6 Mon Sep 17 00:00:00 2001 From: Zhenwen Dai Date: Tue, 3 Nov 2015 15:09:59 +0000 Subject: [PATCH 05/40] add sample_W to SSGPLVM --- GPy/models/ss_gplvm.py | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/GPy/models/ss_gplvm.py b/GPy/models/ss_gplvm.py index 4ccf58ac..0123d629 100644 --- a/GPy/models/ss_gplvm.py +++ b/GPy/models/ss_gplvm.py @@ -190,4 +190,38 @@ class SSGPLVM(SparseGP_MPI): if self.kern.ARD: return self.kern.input_sensitivity() else: - return self.variational_prior.pi \ No newline at end of file + 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) + + + + + \ No newline at end of file From 3a3f6cee44af185979fdd7e6303816e4e0978f6a Mon Sep 17 00:00:00 2001 From: Zhenwen Dai Date: Thu, 12 Nov 2015 15:11:20 +0000 Subject: [PATCH 06/40] enhance optimize parallel --- GPy/util/parallel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPy/util/parallel.py b/GPy/util/parallel.py index 0c99287c..de36f780 100644 --- a/GPy/util/parallel.py +++ b/GPy/util/parallel.py @@ -29,14 +29,14 @@ def divide_data(datanum, rank, size): offset = size*rank+residue 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 datetime import datetime import os if name is None: name = model.name stop = 0 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: timenow = datetime.now() timestr = timenow.strftime('%Y:%m:%d_%H:%M:%S') From 4f1328980c693a325bf57c76e982535938e236eb Mon Sep 17 00:00:00 2001 From: Zhenwen Dai Date: Sun, 15 Nov 2015 23:11:00 +0000 Subject: [PATCH 07/40] enable rbf gpu to support psi2n --- GPy/kern/src/psi_comp/rbf_psi_gpucomp.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GPy/kern/src/psi_comp/rbf_psi_gpucomp.py b/GPy/kern/src/psi_comp/rbf_psi_gpucomp.py index 30312d68..ea0b1673 100644 --- a/GPy/kern/src/psi_comp/rbf_psi_gpucomp.py +++ b/GPy/kern/src/psi_comp/rbf_psi_gpucomp.py @@ -360,7 +360,10 @@ class PSICOMP_RBF_GPU(PSICOMP_RBF): if self.GPU_direct: return psi0, psi1_gpu, psi2_gpu 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): try: From 4819b76d36645a861b74f74952012e088eea488c Mon Sep 17 00:00:00 2001 From: Zhenwen Dai Date: Mon, 16 Nov 2015 22:07:45 +0000 Subject: [PATCH 08/40] increase default quadrature points --- GPy/kern/src/psi_comp/gaussherm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPy/kern/src/psi_comp/gaussherm.py b/GPy/kern/src/psi_comp/gaussherm.py index 35eab724..c491983b 100644 --- a/GPy/kern/src/psi_comp/gaussherm.py +++ b/GPy/kern/src/psi_comp/gaussherm.py @@ -16,7 +16,7 @@ from . import 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.cache_K = cache_K self.locs, self.weights = np.polynomial.hermite.hermgauss(degree) From 849da9d5f4488bbfb89f12c8978e83be8d1cdc4c Mon Sep 17 00:00:00 2001 From: Zhenwen Dai Date: Wed, 9 Dec 2015 17:32:21 +0000 Subject: [PATCH 09/40] mark the kernel test for independent kernel and hierarchical kernel as expectedFailure --- GPy/testing/kernel_tests.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GPy/testing/kernel_tests.py b/GPy/testing/kernel_tests.py index 2eebb6e3..bae7b2e4 100644 --- a/GPy/testing/kernel_tests.py +++ b/GPy/testing/kernel_tests.py @@ -366,6 +366,7 @@ class KernelTestsNonContinuous(unittest.TestCase): self.X2[:(N0*2), -1] = 0 self.X2[(N0*2):, -1] = 1 + @unittest.expectedFailure def test_IndependentOutputs(self): k = GPy.kern.RBF(self.D, active_dims=range(self.D)) kern = GPy.kern.IndependentOutputs(k, -1, 'ind_single') @@ -374,6 +375,7 @@ class KernelTestsNonContinuous(unittest.TestCase): 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)) + @unittest.expectedFailure 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')] kern = GPy.kern.IndependentOutputs(k, -1, name='ind_split') From 82f888f89cc33a8446321ee23d5af0a11b0e0400 Mon Sep 17 00:00:00 2001 From: cdguarnizo Date: Tue, 5 Jan 2016 15:15:09 -0500 Subject: [PATCH 10/40] Changed add_paraters to link_paramters --- GPy/kern/src/ODE_UYC.py | 2 +- GPy/kern/src/ODE_st.py | 2 +- GPy/kern/src/ODE_t.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GPy/kern/src/ODE_UYC.py b/GPy/kern/src/ODE_UYC.py index d02eb1d9..57c41767 100644 --- a/GPy/kern/src/ODE_UYC.py +++ b/GPy/kern/src/ODE_UYC.py @@ -18,7 +18,7 @@ class ODE_UYC(Kern): self.lengthscale_U = Param('lengthscale_U', lengthscale_U, 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): # model : a * dy/dt + b * y = U diff --git a/GPy/kern/src/ODE_st.py b/GPy/kern/src/ODE_st.py index f9d4e684..0b4fecae 100644 --- a/GPy/kern/src/ODE_st.py +++ b/GPy/kern/src/ODE_st.py @@ -38,7 +38,7 @@ class ODE_st(Kern): self.b = Param('b', b, 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): diff --git a/GPy/kern/src/ODE_t.py b/GPy/kern/src/ODE_t.py index ffd349ec..d5dae665 100644 --- a/GPy/kern/src/ODE_t.py +++ b/GPy/kern/src/ODE_t.py @@ -17,7 +17,7 @@ class ODE_t(Kern): self.a= Param('a', a, Logexp()) self.c = Param('c', c, 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): """Compute the covariance matrix between X and X2.""" From d8b5a72ea824f4061344eaba3bff4cafe8e1f3d1 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Mon, 11 Jan 2016 16:13:13 +0000 Subject: [PATCH 11/40] [plotting] was failing on some 3 dimensional plots (latent) --- GPy/kern/__init__.py | 2 +- GPy/plotting/gpy_plot/latent_plots.py | 32 +++++---- GPy/plotting/matplot_dep/plot_definitions.py | 70 ++++++++++---------- 3 files changed, 51 insertions(+), 53 deletions(-) diff --git a/GPy/kern/__init__.py b/GPy/kern/__init__.py index f8f7d016..e2990f99 100644 --- a/GPy/kern/__init__.py +++ b/GPy/kern/__init__.py @@ -28,4 +28,4 @@ from .src.trunclinear import TruncLinear,TruncLinear_inf from .src.splitKern import SplitKern,DEtime from .src.splitKern import DEtime as DiffGenomeKern from .src.spline import Spline -from .src.basis_funcs import LinearSlopeBasisFuncKernel, BasisFuncKernel, ChangePointBasisFuncKernel, DomainKernel \ No newline at end of file +from .src.basis_funcs import LogisticBasisFuncKernel, LinearSlopeBasisFuncKernel, BasisFuncKernel, ChangePointBasisFuncKernel, DomainKernel \ No newline at end of file diff --git a/GPy/plotting/gpy_plot/latent_plots.py b/GPy/plotting/gpy_plot/latent_plots.py index 240f35ae..976641b2 100644 --- a/GPy/plotting/gpy_plot/latent_plots.py +++ b/GPy/plotting/gpy_plot/latent_plots.py @@ -50,6 +50,19 @@ def _wait_for_updates(view, updates): # No updateable view: 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 + 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) + return canvas, projection, kwargs, sig_dims def _plot_latent_scatter(canvas, X, visible_dims, labels, marker, num_samples, projection='2d', **kwargs): from .. import Tango @@ -85,12 +98,8 @@ def plot_latent_scatter(self, labels=None, :param str marker: markers to use - cycle if more labels then markers are given :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) if labels is None: labels = np.ones(self.num_data) @@ -101,8 +110,6 @@ def plot_latent_scatter(self, labels=None, return pl().add_to_canvas(canvas, dict(scatter=scatters), legend=legend) - - def plot_latent_inducing(self, which_indices=None, legend=False, @@ -122,17 +129,8 @@ def plot_latent_inducing(self, :param str marker: markers to use - cycle if more labels then markers are given :param kwargs: the kwargs for the scatter plots """ - 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, projection, kwargs, sig_dims = _new_canvas(self, projection, kwargs, which_indices) - 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 labels = np.array(['inducing'] * Z.shape[0]) scatters = _plot_latent_scatter(canvas, Z, sig_dims, labels, marker, num_samples, projection=projection, **kwargs) diff --git a/GPy/plotting/matplot_dep/plot_definitions.py b/GPy/plotting/matplot_dep/plot_definitions.py index a33e6bbe..9eb9efb0 100644 --- a/GPy/plotting/matplot_dep/plot_definitions.py +++ b/GPy/plotting/matplot_dep/plot_definitions.py @@ -1,21 +1,21 @@ #=============================================================================== # Copyright (c) 2015, Max Zwiessele # All rights reserved. -# +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: -# +# # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. -# +# # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. -# +# # * Neither the name of GPy.plotting.matplot_dep.plot_definitions nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. -# +# # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -41,14 +41,14 @@ class MatplotlibPlots(AbstractPlottingLibrary): def __init__(self): super(MatplotlibPlots, self).__init__() self._defaults = defaults.__dict__ - + def figure(self, rows=1, cols=1, **kwargs): fig = plt.figure(**kwargs) fig.rows = rows fig.cols = cols 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': from mpl_toolkits.mplot3d import Axes3D elif projection == '2d': @@ -64,10 +64,10 @@ class MatplotlibPlots(AbstractPlottingLibrary): fig = self.figure(figsize=kwargs.pop('figsize')) else: fig = self.figure() - + #if hasattr(fig, 'rows') and hasattr(fig, 'cols'): ax = fig.add_subplot(fig.rows, fig.cols, (col,row), projection=projection) - + if xlim is not None: ax.set_xlim(xlim) if ylim is not None: ax.set_ylim(ylim) if xlabel is not None: ax.set_xlabel(xlabel) @@ -77,7 +77,7 @@ class MatplotlibPlots(AbstractPlottingLibrary): if zlim is not None: ax.set_zlim(zlim) if zlabel is not None: ax.set_zlabel(zlabel) return ax, kwargs - + def add_to_canvas(self, ax, plots, legend=False, title=None, **kwargs): ax.autoscale_view() fontdict=dict(family='sans-serif', weight='light', size=9) @@ -88,18 +88,18 @@ class MatplotlibPlots(AbstractPlottingLibrary): legend_ontop(ax, ncol=legend, fontdict=fontdict) if title is not None: ax.figure.suptitle(title) return ax - + def show_canvas(self, ax, tight_layout=False, **kwargs): if tight_layout: ax.figure.tight_layout() ax.figure.canvas.draw() return ax.figure - + def scatter(self, ax, X, Y, Z=None, color=Tango.colorsHex['mediumBlue'], label=None, marker='o', **kwargs): if Z is not None: return ax.scatter(X, Y, c=color, zs=Z, label=label, marker=marker, **kwargs) return ax.scatter(X, Y, c=color, label=label, marker=marker, **kwargs) - + def plot(self, ax, X, Y, Z=None, color=None, label=None, **kwargs): if Z is not None: return ax.plot(X, Y, color=color, zs=Z, label=label, **kwargs) @@ -122,23 +122,23 @@ class MatplotlibPlots(AbstractPlottingLibrary): if 'align' not in kwargs: kwargs['align'] = 'center' return ax.bar(left=x, height=height, width=width, - bottom=bottom, label=label, color=color, + bottom=bottom, label=label, color=color, **kwargs) - + def xerrorbar(self, ax, X, Y, error, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs): if not('linestyle' in kwargs or 'ls' in kwargs): kwargs['ls'] = 'none' #if Z is not None: # return ax.errorbar(X, Y, Z, xerr=error, ecolor=color, label=label, **kwargs) return ax.errorbar(X, Y, xerr=error, ecolor=color, label=label, **kwargs) - + def yerrorbar(self, ax, X, Y, error, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs): if not('linestyle' in kwargs or 'ls' in kwargs): kwargs['ls'] = 'none' #if Z is not None: # return ax.errorbar(X, Y, Z, yerr=error, ecolor=color, label=label, **kwargs) return ax.errorbar(X, Y, yerr=error, ecolor=color, label=label, **kwargs) - + def imshow(self, ax, X, extent=None, label=None, vmin=None, vmax=None, **imshow_kwargs): if 'origin' not in imshow_kwargs: imshow_kwargs['origin'] = 'lower' @@ -178,7 +178,7 @@ class MatplotlibPlots(AbstractPlottingLibrary): if 'origin' not in imshow_kwargs: imshow_kwargs['origin'] = 'lower' return ImAnnotateController(ax, plot_function, extent, resolution=resolution, imshow_kwargs=imshow_kwargs or {}, **annotation_kwargs) - + def contour(self, ax, X, Y, C, levels=20, label=None, **kwargs): return ax.contour(X, Y, C, levels=np.linspace(C.min(), C.max(), levels), label=label, **kwargs) @@ -191,13 +191,13 @@ class MatplotlibPlots(AbstractPlottingLibrary): def fill_gradient(self, canvas, X, percentiles, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs): ax = canvas plots = [] - + if 'edgecolors' not in kwargs: kwargs['edgecolors'] = 'none' - + if 'facecolors' in kwargs: color = kwargs.pop('facecolors') - + if 'array' in kwargs: array = kwargs.pop('array') else: @@ -231,8 +231,8 @@ class MatplotlibPlots(AbstractPlottingLibrary): # pass a, b = tee(iterable) next(b, None) - return zip(a, b) - + return zip(a, b) + polycol = [] for y1, y2 in pairwise(percentiles): import matplotlib.mlab as mlab @@ -244,51 +244,51 @@ class MatplotlibPlots(AbstractPlottingLibrary): 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") - + from functools import reduce 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) p = 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] - + p[0] = start p[N + 1] = end - + p[1:N + 1, 0] = xslice p[1:N + 1, 1] = y1slice p[N + 2:, 0] = xslice[::-1] p[N + 2:, 1] = y2slice[::-1] - + polys.append(p) polycol.extend(polys) from matplotlib.collections import PolyCollection From b2ec4ae765a35cd498b7c96523a61bc3ab4173ea Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Mon, 11 Jan 2016 16:44:13 +0000 Subject: [PATCH 12/40] [plotting] baseline updates for 3d plotting --- .../baseline/bayesian_gplvm_latent_3d.png | Bin 8832 -> 9214 bytes GPy/testing/baseline/gplvm_latent_3d.png | Bin 8832 -> 9214 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/GPy/testing/baseline/bayesian_gplvm_latent_3d.png b/GPy/testing/baseline/bayesian_gplvm_latent_3d.png index 795e89f94e15b3f436a01cdf2ab06d52bb4ea053..ea0009f26d9de58c086270fb6eaf3a5d7f324437 100644 GIT binary patch literal 9214 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 literal 8832 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 literal 8832 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 Date: Mon, 11 Jan 2016 16:44:56 +0000 Subject: [PATCH 13/40] [plotting] skipping plotting tests, as they are inconsistent across platforms --- GPy/testing/plotting_tests.py | 54 ++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/GPy/testing/plotting_tests.py b/GPy/testing/plotting_tests.py index f833faf0..441854d4 100644 --- a/GPy/testing/plotting_tests.py +++ b/GPy/testing/plotting_tests.py @@ -27,13 +27,21 @@ # 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. #=============================================================================== + + +#=============================================================================== +# SKIPPING PLOTTING BECAUSE IT BEHAVES DIFFERENTLY ON DIFFERENT +# SYSTEMS, AND WILL MISBEHAVE +from nose import SkipTest +raise SkipTest("Skipping Matplotlib testing") +#=============================================================================== + import matplotlib from unittest.case import TestCase matplotlib.use('agg') import numpy as np import GPy, os -from nose import SkipTest from GPy.util.config import config from GPy.plotting import change_plotting_library, plotting_library @@ -41,7 +49,7 @@ from GPy.plotting import change_plotting_library, plotting_library class ConfigTest(TestCase): def tearDown(self): change_plotting_library('matplotlib') - + def test_change_plotting(self): self.assertRaises(ValueError, change_plotting_library, 'not+in9names') change_plotting_library('none') @@ -115,12 +123,12 @@ def test_figure(): import warnings with warnings.catch_warnings(): warnings.simplefilter("ignore") - + ax, _ = pl().new_canvas(num=1) def test_func(x): return x[:, 0].reshape(3,3) pl().imshow_interact(ax, test_func, extent=(-1,1,-1,1), resolution=3) - + ax, _ = pl().new_canvas() def test_func_2(x): y = x[:, 0].reshape(3,3) @@ -129,21 +137,21 @@ def test_figure(): pl().annotation_heatmap_interact(ax, test_func_2, extent=(-1,1,-1,1), resolution=3) pl().annotation_heatmap_interact(ax, test_func_2, extent=(-1,1,-1,1), resolution=3, imshow_kwargs=dict(interpolation='nearest')) - + ax, _ = pl().new_canvas(figsize=(4,3)) x = np.linspace(0,1,100) y = [0,1,2] array = np.array([.4,.5]) cmap = matplotlib.colors.LinearSegmentedColormap.from_list('WhToColor', ('r', 'b'), N=array.size) - pl().fill_gradient(ax, x, y, facecolors=['r', 'g'], array=array, cmap=cmap) - + pl().fill_gradient(ax, x, y, facecolors=['r', 'g'], array=array, cmap=cmap) + ax, _ = pl().new_canvas(num=4, figsize=(4,3), projection='3d', xlabel='x', ylabel='y', zlabel='z', title='awsome title', xlim=(-1,1), ylim=(-1,1), zlim=(-3,3)) z = 2-np.abs(np.linspace(-2,2,(100)))+1 x, y = z*np.sin(np.linspace(-2*np.pi,2*np.pi,(100))), z*np.cos(np.linspace(-np.pi,np.pi,(100))) - + pl().plot(ax, x, y, z, linewidth=2) - + for do_test in _image_comparison( baseline_images=['coverage_{}'.format(sub) for sub in ["imshow_interact",'annotation_interact','gradient','3d_plot',]], extensions=extensions): @@ -194,9 +202,9 @@ def test_plot(): m.plot_errorbars_trainset() m.plot_samples() m.plot_data_error() - for do_test in _image_comparison(baseline_images=['gp_{}'.format(sub) for sub in ["data", "mean", 'conf', - 'density', - 'out_error', + for do_test in _image_comparison(baseline_images=['gp_{}'.format(sub) for sub in ["data", "mean", 'conf', + 'density', + 'out_error', 'samples', 'in_error']], extensions=extensions): yield (do_test, ) @@ -216,9 +224,9 @@ def test_twod(): m.plot_inducing() #m.plot_errorbars_trainset() m.plot_data_error() - for do_test in _image_comparison(baseline_images=['gp_2d_{}'.format(sub) for sub in ["data", "mean", - 'inducing', - #'out_error', + for do_test in _image_comparison(baseline_images=['gp_2d_{}'.format(sub) for sub in ["data", "mean", + 'inducing', + #'out_error', 'in_error', ]], extensions=extensions): yield (do_test, ) @@ -242,7 +250,7 @@ def test_threed(): m.plot_mean(projection='3d') m.plot_inducing(projection='3d') #m.plot_errorbars_trainset(projection='3d') - for do_test in _image_comparison(baseline_images=['gp_3d_{}'.format(sub) for sub in ["data", "mean", 'inducing', + for do_test in _image_comparison(baseline_images=['gp_3d_{}'.format(sub) for sub in ["data", "mean", 'inducing', #'error', #"samples", "samples_lik" ]], extensions=extensions): @@ -316,7 +324,7 @@ def test_gplvm(): matplotlib.rcParams[u'figure.figsize'] = (4,3) matplotlib.rcParams[u'text.usetex'] = False Q = 3 - # Define dataset + # Define dataset N = 10 k1 = GPy.kern.RBF(5, variance=1, lengthscale=1./np.random.dirichlet(np.r_[10,10,10,0.1,0.1]), ARD=True) k2 = GPy.kern.RBF(5, variance=1, lengthscale=1./np.random.dirichlet(np.r_[10,0.1,10,0.1,10]), ARD=True) @@ -325,10 +333,10 @@ def test_gplvm(): A = np.random.multivariate_normal(np.zeros(N), k1.K(X), Q).T B = np.random.multivariate_normal(np.zeros(N), k2.K(X), Q).T C = np.random.multivariate_normal(np.zeros(N), k3.K(X), Q).T - + Y = np.vstack((A,B,C)) labels = np.hstack((np.zeros(A.shape[0]), np.ones(B.shape[0]), np.ones(C.shape[0])*2)) - + k = RBF(Q, ARD=True, lengthscale=2) # + kern.white(Q, _np.exp(-2)) # + kern.bias(Q) m = GPLVM(Y, Q, init="PCA", kernel=k) m.kern.lengthscale[:] = [1./.3, 1./.1, 1./.7] @@ -341,7 +349,7 @@ def test_gplvm(): np.random.seed(111) m.plot_magnification(labels=labels) m.plot_steepest_gradient_map(resolution=10, data_labels=labels) - for do_test in _image_comparison(baseline_images=['gplvm_{}'.format(sub) for sub in ["latent", "latent_3d", "magnification", 'gradient']], + for do_test in _image_comparison(baseline_images=['gplvm_{}'.format(sub) for sub in ["latent", "latent_3d", "magnification", 'gradient']], extensions=extensions, tol=12): yield (do_test, ) @@ -355,7 +363,7 @@ def test_bayesian_gplvm(): matplotlib.rcParams[u'figure.figsize'] = (4,3) matplotlib.rcParams[u'text.usetex'] = False Q = 3 - # Define dataset + # Define dataset N = 10 k1 = GPy.kern.RBF(5, variance=1, lengthscale=1./np.random.dirichlet(np.r_[10,10,10,0.1,0.1]), ARD=True) k2 = GPy.kern.RBF(5, variance=1, lengthscale=1./np.random.dirichlet(np.r_[10,0.1,10,0.1,10]), ARD=True) @@ -364,10 +372,10 @@ def test_bayesian_gplvm(): A = np.random.multivariate_normal(np.zeros(N), k1.K(X), Q).T B = np.random.multivariate_normal(np.zeros(N), k2.K(X), Q).T C = np.random.multivariate_normal(np.zeros(N), k3.K(X), Q).T - + Y = np.vstack((A,B,C)) labels = np.hstack((np.zeros(A.shape[0]), np.ones(B.shape[0]), np.ones(C.shape[0])*2)) - + k = RBF(Q, ARD=True, lengthscale=2) # + kern.white(Q, _np.exp(-2)) # + kern.bias(Q) m = BayesianGPLVM(Y, Q, init="PCA", kernel=k) m.kern.lengthscale[:] = [1./.3, 1./.1, 1./.7] From e75f78d7023cbc5ce772cfb7c29bd23e6fd4e4ad Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Mon, 11 Jan 2016 16:52:40 +0000 Subject: [PATCH 14/40] =?UTF-8?q?Bump=20version:=200.9.4=20=E2=86=92=200.9?= =?UTF-8?q?.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GPy/__version__.py | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GPy/__version__.py b/GPy/__version__.py index e94731c0..f8c6ac7f 100644 --- a/GPy/__version__.py +++ b/GPy/__version__.py @@ -1 +1 @@ -__version__ = "0.9.4" +__version__ = "0.9.5" diff --git a/setup.cfg b/setup.cfg index 0b515a11..c8c61b7b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.9.4 +current_version = 0.9.5 tag = True commit = True From e917da8cceb871653c8fded1ecdcac963a74d79c Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Tue, 12 Jan 2016 12:33:13 +0000 Subject: [PATCH 15/40] [plotting] catching 3d error for plotting latent space in other then 2 dimensions --- GPy/plotting/gpy_plot/latent_plots.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GPy/plotting/gpy_plot/latent_plots.py b/GPy/plotting/gpy_plot/latent_plots.py index 976641b2..85a98f49 100644 --- a/GPy/plotting/gpy_plot/latent_plots.py +++ b/GPy/plotting/gpy_plot/latent_plots.py @@ -229,7 +229,7 @@ def plot_latent(self, labels=None, which_indices=None, plot_limits=None, updates=False, kern=None, marker='<>^vsd', - num_samples=1000, + num_samples=1000, projection='2d', scatter_kwargs=None, **imshow_kwargs): """ Plot the latent space of the GP on the inputs. This is the @@ -249,6 +249,8 @@ def plot_latent(self, labels=None, which_indices=None, :param imshow_kwargs: the kwargs for the imshow (magnification factor) :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] X = get_x_y_var(self)[0] _, _, Xgrid, _, _, xmin, xmax, resolution = helper_for_plot_data(self, X, plot_limits, which_indices, None, resolution) From f68001a84e281d437b5dc05550528ae8e4056eb0 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Tue, 12 Jan 2016 12:33:42 +0000 Subject: [PATCH 16/40] [vardtc] these two lines are overridden by the next two lines... --- GPy/inference/latent_function_inference/var_dtc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPy/inference/latent_function_inference/var_dtc.py b/GPy/inference/latent_function_inference/var_dtc.py index e05dbaf9..ec055120 100644 --- a/GPy/inference/latent_function_inference/var_dtc.py +++ b/GPy/inference/latent_function_inference/var_dtc.py @@ -190,8 +190,8 @@ class VarDTC(LatentFunctionInference): tmp, _ = dtrtrs(Lm, psi1V, lower=1, trans=0) tmp, _ = dpotrs(LB, tmp, lower=1) woodbury_vector, _ = dtrtrs(Lm, tmp, lower=1, trans=1) - Bi, _ = dpotri(LB, lower=1) - symmetrify(Bi) + #Bi, _ = dpotri(LB, lower=1) + #symmetrify(Bi) Bi = -dpotri(LB, lower=1)[0] diag.add(Bi, 1) From 4461e35c9e3bf8cae609d4d96ba9552d6b9dd904 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Tue, 12 Jan 2016 13:42:41 +0000 Subject: [PATCH 17/40] [plotly] scatter plotting was defaulting to color='white' --- GPy/plotting/gpy_plot/latent_plots.py | 2 -- GPy/plotting/plotly_dep/defaults.py | 2 +- GPy/plotting/plotly_dep/plot_definitions.py | 29 +++++++++++---------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/GPy/plotting/gpy_plot/latent_plots.py b/GPy/plotting/gpy_plot/latent_plots.py index 85a98f49..ed12ad9a 100644 --- a/GPy/plotting/gpy_plot/latent_plots.py +++ b/GPy/plotting/gpy_plot/latent_plots.py @@ -57,8 +57,6 @@ def _new_canvas(self, projection, kwargs, which_indices): 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) diff --git a/GPy/plotting/plotly_dep/defaults.py b/GPy/plotting/plotly_dep/defaults.py index faf343b0..24170b95 100644 --- a/GPy/plotting/plotly_dep/defaults.py +++ b/GPy/plotting/plotly_dep/defaults.py @@ -72,5 +72,5 @@ ard = dict(linewidth=1.2, barmode='stack') latent = dict(colorscale='Greys', reversescale=True, zsmooth='best') gradient = dict(colorscale='RdBu', opacity=.7) 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) \ No newline at end of file diff --git a/GPy/plotting/plotly_dep/plot_definitions.py b/GPy/plotting/plotly_dep/plot_definitions.py index 613cdf4c..54f04a75 100644 --- a/GPy/plotting/plotly_dep/plot_definitions.py +++ b/GPy/plotting/plotly_dep/plot_definitions.py @@ -130,14 +130,15 @@ class PlotlyPlots(AbstractPlottingLibrary): except: #not matplotlib marker pass + marker_kwargs = marker_kwargs or {} marker_kwargs.setdefault('symbol', marker) if Z is not None: - return Scatter3d(x=X, y=Y, z=Z, mode='markers', - showlegend=label is not None, - marker=Marker(color=color, colorscale=cmap, **marker_kwargs or {}), + return Scatter3d(x=X, y=Y, z=Z, mode='markers', + showlegend=label is not None, + marker=Marker(color=color, colorscale=cmap, **marker_kwargs), name=label, **kwargs) - return Scatter(x=X, y=Y, mode='markers', showlegend=label is not None, - marker=Marker(color=color, colorscale=cmap, **marker_kwargs or {}), + return Scatter(x=X, y=Y, mode='markers', showlegend=label is not None, + marker=Marker(color=color, colorscale=cmap, **marker_kwargs or {}), name=label, **kwargs) def plot(self, ax, X, Y, Z=None, color=None, label=None, line_kwargs=None, **kwargs): @@ -169,10 +170,10 @@ class PlotlyPlots(AbstractPlottingLibrary): elif X.shape[1] == 2: marker_kwargs.setdefault('symbol', 'diamond') opacity = kwargs.pop('opacity', .8) - return Scatter3d(x=X[:, 0], y=X[:, 1], z=np.zeros(X.shape[0]), + return Scatter3d(x=X[:, 0], y=X[:, 1], z=np.zeros(X.shape[0]), mode='markers', - projection=dict(z=dict(show=True, opacity=opacity)), - marker=Marker(color=color, **marker_kwargs or {}), + projection=dict(z=dict(show=True, opacity=opacity)), + marker=Marker(color=color, **marker_kwargs or {}), opacity=0, name=label, showlegend=label is not None, **kwargs) @@ -284,11 +285,11 @@ class PlotlyPlots(AbstractPlottingLibrary): if color.startswith('#'): colarray = Tango.hex2rgb(color) opacity = .9 - else: + else: colarray = map(float(color.strip(')').split('(')[1])) if len(colarray) == 4: colarray, opacity = colarray[:3] ,colarray[3] - + alpha = opacity*(1.-np.abs(np.linspace(-1,1,len(percentiles)-1))) def pairwise(iterable): @@ -302,11 +303,11 @@ class PlotlyPlots(AbstractPlottingLibrary): for i, y1, a in zip(range(len(percentiles)), percentiles, alpha): fcolor = 'rgba({}, {}, {}, {alpha})'.format(*colarray, alpha=a) if i == len(percentiles)/2: - polycol.append(Scatter(x=X, y=y1, fillcolor=fcolor, showlegend=True, - name=label, line=Line(width=0, smoothing=0), mode='none', fill='tonextx', + polycol.append(Scatter(x=X, y=y1, fillcolor=fcolor, showlegend=True, + name=label, line=Line(width=0, smoothing=0), mode='none', fill='tonextx', legendgroup='density', hoverinfo='none', **kwargs)) else: - polycol.append(Scatter(x=X, y=y1, fillcolor=fcolor, showlegend=False, - name=None, line=Line(width=1, smoothing=0, color=fcolor), mode='none', fill='tonextx', + polycol.append(Scatter(x=X, y=y1, fillcolor=fcolor, showlegend=False, + name=None, line=Line(width=1, smoothing=0, color=fcolor), mode='none', fill='tonextx', legendgroup='density', hoverinfo='none', **kwargs)) return polycol From 023a01175a1eb10193372951df52f0c8ce354bac Mon Sep 17 00:00:00 2001 From: Alan Saul Date: Fri, 15 Jan 2016 15:11:34 +0000 Subject: [PATCH 18/40] Added paramz to requirement file for docs --- doc/source/requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/source/requirements.txt diff --git a/doc/source/requirements.txt b/doc/source/requirements.txt new file mode 100644 index 00000000..d5f47c6b --- /dev/null +++ b/doc/source/requirements.txt @@ -0,0 +1 @@ +paramz From 1bda209469444f2528350c6eb45b8368883bd953 Mon Sep 17 00:00:00 2001 From: Alan Saul Date: Fri, 15 Jan 2016 15:27:51 +0000 Subject: [PATCH 19/40] Apidoc in conf --- doc/source/conf.py | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index d6220a89..0885c380 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -24,6 +24,32 @@ import shlex sys.path.insert(0, os.path.abspath('../../')) 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 ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -51,10 +77,10 @@ extensions = [ # def __getattr__(cls, name): # return Mock() # -MOCK_MODULES = ['scipy.linalg.blas', 'blas', 'scipy.optimize', 'scipy.optimize.linesearch', 'scipy.linalg', +MOCK_MODULES = ['scipy.linalg.blas', 'blas', 'scipy.optimize', 'scipy.optimize.linesearch', 'scipy.linalg', 'scipy', 'scipy.special', 'scipy.integrate', 'scipy.io', 'scipy.stats', - 'sympy', 'sympy.utilities.iterables', 'sympy.utilities.lambdify', - 'sympy.utilities', 'sympy.utilities.codegen', 'sympy.core.cache', + 'sympy', 'sympy.utilities.iterables', 'sympy.utilities.lambdify', + 'sympy.utilities', 'sympy.utilities.codegen', 'sympy.core.cache', 'sympy.core', 'sympy.parsing', 'sympy.parsing.sympy_parser', 'nose', 'nose.tools'] @@ -94,7 +120,7 @@ master_doc = 'index' # General information about the project. project = u'GPy' #author = u'`Humans `_' -author = 'GPy Authors, see https://github.com/SheffieldML/GPy/graphs/contributors' +author = 'GPy Authors, see https://github.com/SheffieldML/GPy/graphs/contributors' copyright = u'2015, '+author # The version info for the project you're documenting, acts as replacement for From 7b5422b6946315a97f18850dd31cffeeff5c85c8 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Fri, 22 Jan 2016 11:26:29 +0000 Subject: [PATCH 20/40] [plotting&kern] bugfixes in plotting and kernel size --- GPy/core/gp.py | 9 +++++---- GPy/kern/src/kern.py | 4 ++-- GPy/kern/src/stationary.py | 4 ++-- GPy/plotting/gpy_plot/gp_plots.py | 16 ++++++++-------- GPy/plotting/gpy_plot/plot_util.py | 5 ++++- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/GPy/core/gp.py b/GPy/core/gp.py index ae710355..ea2ed140 100644 --- a/GPy/core/gp.py +++ b/GPy/core/gp.py @@ -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) 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]): - 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: - dK2_dXdX = kern.gradients_XX([[1.]], Xnew) + dK2_dXdX = kern.gradients_XX(one, Xnew) else: - dK2_dXdX = kern.gradients_XX_diag([[1.]], Xnew) + dK2_dXdX = kern.gradients_XX_diag(one, Xnew) def compute_cov_inner(wi): if full_cov: @@ -458,7 +459,7 @@ class GP(Model): m, v = self._raw_predict(X, full_cov=full_cov, **predict_kwargs) if self.normalizer is not None: m, v = self.normalizer.inverse_mean(m), self.normalizer.inverse_variance(v) - + def sim_one_dim(m, v): if not full_cov: return np.random.multivariate_normal(m.flatten(), np.diag(v.flatten()), size).T diff --git a/GPy/kern/src/kern.py b/GPy/kern/src/kern.py index ad41355f..6a746092 100644 --- a/GPy/kern/src/kern.py +++ b/GPy/kern/src/kern.py @@ -61,12 +61,12 @@ class Kern(Parameterized): self.psicomp = PSICOMP_GH() 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) @property def _effective_input_dim(self): - return self._all_dims_active.size + return np.size(self._all_dims_active) @Cache_this(limit=20) def _slice_X(self, X): diff --git a/GPy/kern/src/stationary.py b/GPy/kern/src/stationary.py index 106e0098..7b4c3625 100644 --- a/GPy/kern/src/stationary.py +++ b/GPy/kern/src/stationary.py @@ -97,7 +97,7 @@ class Stationary(Kern): r = self._scaled_dist(X, X2) 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): #a convenience function, so we can cache dK_dr return self.dK_dr(self._scaled_dist(X, X2)) @@ -127,7 +127,7 @@ class Stationary(Kern): r2 = np.clip(r2, 0, np.inf) return np.sqrt(r2) - @Cache_this(limit=20, ignore_args=()) + @Cache_this(limit=3, ignore_args=()) def _scaled_dist(self, X, X2=None): """ Efficiently compute the scaled distance, r. diff --git a/GPy/plotting/gpy_plot/gp_plots.py b/GPy/plotting/gpy_plot/gp_plots.py index 4d467e62..353dc7fb 100644 --- a/GPy/plotting/gpy_plot/gp_plots.py +++ b/GPy/plotting/gpy_plot/gp_plots.py @@ -46,7 +46,7 @@ def plot_mean(self, plot_limits=None, fixed_inputs=None, """ Plot the mean of the GP. - You can deactivate the legend for this one plot by supplying None to label. + You can deactivate the legend for this one plot by supplying None to label. Give the Y_metadata in the predict_kw if you need it. @@ -116,7 +116,7 @@ def plot_confidence(self, lower=2.5, upper=97.5, plot_limits=None, fixed_inputs= E.g. the 95% confidence interval is $2.5, 97.5$. Note: Only implemented for one dimension! - You can deactivate the legend for this one plot by supplying None to label. + You can deactivate the legend for this one plot by supplying None to label. Give the Y_metadata in the predict_kw if you need it. @@ -170,7 +170,7 @@ def plot_samples(self, plot_limits=None, fixed_inputs=None, """ Plot the mean of the GP. - You can deactivate the legend for this one plot by supplying None to label. + You can deactivate the legend for this one plot by supplying None to label. Give the Y_metadata in the predict_kw if you need it. @@ -231,7 +231,7 @@ def plot_density(self, plot_limits=None, fixed_inputs=None, E.g. the 95% confidence interval is $2.5, 97.5$. Note: Only implemented for one dimension! - You can deactivate the legend for this one plot by supplying None to label. + You can deactivate the legend for this one plot by supplying None to label. Give the Y_metadata in the predict_kw if you need it. @@ -288,7 +288,7 @@ def plot(self, plot_limits=None, fixed_inputs=None, """ Convenience function for plotting the fit of a GP. - You can deactivate the legend for this one plot by supplying None to label. + You can deactivate the legend for this one plot by supplying None to label. Give the Y_metadata in the predict_kw if you need it. @@ -330,6 +330,8 @@ 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. plot_data = False plots = {} + if hasattr(self, 'Z') and plot_inducing: + plots.update(_plot_inducing(self, canvas, visible_dims, projection, 'Inducing')) if plot_data: plots.update(_plot_data(self, canvas, which_data_rows, which_data_ycols, visible_dims, projection, "Data")) plots.update(_plot_data_error(self, canvas, which_data_rows, which_data_ycols, visible_dims, projection, "Data Error")) @@ -340,8 +342,6 @@ def plot(self, plot_limits=None, fixed_inputs=None, get_which_data_ycols(self, which_data_ycols), predict_kw, samples_likelihood) 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) @@ -362,7 +362,7 @@ def plot_f(self, plot_limits=None, fixed_inputs=None, If you want fine graned control use the specific plotting functions supplied in the model. - You can deactivate the legend for this one plot by supplying None to label. + You can deactivate the legend for this one plot by supplying None to label. Give the Y_metadata in the predict_kw if you need it. diff --git a/GPy/plotting/gpy_plot/plot_util.py b/GPy/plotting/gpy_plot/plot_util.py index 254886a2..d760d1b7 100644 --- a/GPy/plotting/gpy_plot/plot_util.py +++ b/GPy/plotting/gpy_plot/plot_util.py @@ -285,7 +285,10 @@ def get_x_y_var(model): X = model.X.mean.values X_variance = model.X.variance.values else: - X = model.X.values + try: + X = model.X.values + except AttributeError: + X = model.X X_variance = None try: Y = model.Y.values From 095a8607b29c392d1e91f1395e286155e8427fa1 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Fri, 22 Jan 2016 11:26:53 +0000 Subject: [PATCH 21/40] =?UTF-8?q?Bump=20version:=200.9.5=20=E2=86=92=200.9?= =?UTF-8?q?.6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GPy/__version__.py | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GPy/__version__.py b/GPy/__version__.py index f8c6ac7f..50533e30 100644 --- a/GPy/__version__.py +++ b/GPy/__version__.py @@ -1 +1 @@ -__version__ = "0.9.5" +__version__ = "0.9.6" diff --git a/setup.cfg b/setup.cfg index c8c61b7b..3a2581bd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.9.5 +current_version = 0.9.6 tag = True commit = True From fd979b843f3a3e758605e8e9b9d06d570abea9ab Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Thu, 28 Jan 2016 12:12:57 +0000 Subject: [PATCH 22/40] [plotting] subsampling print waring corrected --- GPy/plotting/gpy_plot/plot_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPy/plotting/gpy_plot/plot_util.py b/GPy/plotting/gpy_plot/plot_util.py index d760d1b7..a910cd6f 100644 --- a/GPy/plotting/gpy_plot/plot_util.py +++ b/GPy/plotting/gpy_plot/plot_util.py @@ -199,7 +199,7 @@ def subsample_X(X, labels, num_samples=1000): num_samples and the returned subsampled X. """ 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: subsample = [] for _, _, _, _, index, _ in scatter_label_generator(labels, X, (0, None, None)): From 98daaba57e1db392f5fb5af59c74d9832c36309b Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Fri, 19 Feb 2016 14:55:36 +0000 Subject: [PATCH 23/40] [plotting] xlim setting --- GPy/core/gp.py | 2 +- GPy/inference/optimization/optimization.py | 286 --------------------- GPy/plotting/gpy_plot/gp_plots.py | 12 +- 3 files changed, 11 insertions(+), 289 deletions(-) delete mode 100644 GPy/inference/optimization/optimization.py diff --git a/GPy/core/gp.py b/GPy/core/gp.py index ea2ed140..7a29664f 100644 --- a/GPy/core/gp.py +++ b/GPy/core/gp.py @@ -181,7 +181,7 @@ class GP(Model): def parameters_changed(self): """ 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:: 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 diff --git a/GPy/inference/optimization/optimization.py b/GPy/inference/optimization/optimization.py deleted file mode 100644 index ceceb222..00000000 --- a/GPy/inference/optimization/optimization.py +++ /dev/null @@ -1,286 +0,0 @@ -# Copyright (c) 2012-2014, GPy authors (see AUTHORS.txt). -# Licensed under the BSD 3-clause license (see LICENSE.txt) - -import datetime as dt -from scipy import optimize -from warnings import warn - -try: - import rasmussens_minimize as rasm - rasm_available = True -except ImportError: - rasm_available = False -from .scg import SCG - -class Optimizer(object): - """ - Superclass for all the optimizers. - - :param x_init: initial set of parameters - :param f_fp: function that returns the function AND the gradients at the same time - :param f: function to optimize - :param fp: gradients - :param messages: print messages from the optimizer? - :type messages: (True | False) - :param max_f_eval: maximum number of function evaluations - - :rtype: optimizer object. - - """ - def __init__(self, x_init, messages=False, model=None, max_f_eval=1e4, max_iters=1e3, - ftol=None, gtol=None, xtol=None, bfgs_factor=None): - self.opt_name = None - self.x_init = x_init - # Turning messages off and using internal structure for print outs: - self.messages = False #messages - self.f_opt = None - self.x_opt = None - self.funct_eval = None - self.status = None - self.max_f_eval = int(max_iters) - self.max_iters = int(max_iters) - self.bfgs_factor = bfgs_factor - self.trace = None - self.time = "Not available" - self.xtol = xtol - self.gtol = gtol - self.ftol = ftol - self.model = model - - def run(self, **kwargs): - start = dt.datetime.now() - self.opt(**kwargs) - end = dt.datetime.now() - self.time = str(end - start) - - def opt(self, f_fp=None, f=None, fp=None): - raise NotImplementedError("this needs to be implemented to use the optimizer class") - - def __str__(self): - diagnostics = "Optimizer: \t\t\t\t %s\n" % self.opt_name - diagnostics += "f(x_opt): \t\t\t\t %.3f\n" % self.f_opt - diagnostics += "Number of function evaluations: \t %d\n" % self.funct_eval - diagnostics += "Optimization status: \t\t\t %s\n" % self.status - diagnostics += "Time elapsed: \t\t\t\t %s\n" % self.time - return diagnostics - -class opt_tnc(Optimizer): - def __init__(self, *args, **kwargs): - Optimizer.__init__(self, *args, **kwargs) - self.opt_name = "TNC (Scipy implementation)" - - def opt(self, f_fp=None, f=None, fp=None): - """ - Run the TNC optimizer - - """ - tnc_rcstrings = ['Local minimum', 'Converged', 'XConverged', 'Maximum number of f evaluations reached', - 'Line search failed', 'Function is constant'] - - assert f_fp != None, "TNC requires f_fp" - - opt_dict = {} - if self.xtol is not None: - opt_dict['xtol'] = self.xtol - if self.ftol is not None: - opt_dict['ftol'] = self.ftol - if self.gtol is not None: - opt_dict['pgtol'] = self.gtol - - opt_result = optimize.fmin_tnc(f_fp, self.x_init, messages=self.messages, - maxfun=self.max_f_eval, **opt_dict) - self.x_opt = opt_result[0] - self.f_opt = f_fp(self.x_opt)[0] - self.funct_eval = opt_result[1] - self.status = tnc_rcstrings[opt_result[2]] - -class opt_lbfgsb(Optimizer): - def __init__(self, *args, **kwargs): - Optimizer.__init__(self, *args, **kwargs) - self.opt_name = "L-BFGS-B (Scipy implementation)" - - def opt(self, f_fp=None, f=None, fp=None): - """ - Run the optimizer - - """ - rcstrings = ['Converged', 'Maximum number of f evaluations reached', 'Error'] - - assert f_fp != None, "BFGS requires f_fp" - - if self.messages: - iprint = 1 - else: - iprint = -1 - - opt_dict = {} - if self.xtol is not None: - print("WARNING: l-bfgs-b doesn't have an xtol arg, so I'm going to ignore it") - if self.ftol is not None: - print("WARNING: l-bfgs-b doesn't have an ftol arg, so I'm going to ignore it") - if self.gtol is not None: - opt_dict['pgtol'] = self.gtol - if self.bfgs_factor is not None: - opt_dict['factr'] = self.bfgs_factor - - opt_result = optimize.fmin_l_bfgs_b(f_fp, self.x_init, iprint=iprint, - maxfun=self.max_iters,maxiter=self.max_iters, **opt_dict) - self.x_opt = opt_result[0] - self.f_opt = f_fp(self.x_opt)[0] - self.funct_eval = opt_result[2]['funcalls'] - self.status = rcstrings[opt_result[2]['warnflag']] - - #a more helpful error message is available in opt_result in the Error case - if opt_result[2]['warnflag']==2: - self.status = 'Error' + str(opt_result[2]['task']) - -class opt_bfgs(Optimizer): - def __init__(self, *args, **kwargs): - Optimizer.__init__(self, *args, **kwargs) - self.opt_name = "BFGS (Scipy implementation)" - - def opt(self, f_fp=None, f=None, fp=None): - """ - Run the optimizer - - """ - rcstrings = ['','Maximum number of iterations exceeded', 'Gradient and/or function calls not changing'] - - opt_dict = {} - if self.xtol is not None: - print("WARNING: bfgs doesn't have an xtol arg, so I'm going to ignore it") - if self.ftol is not None: - print("WARNING: bfgs doesn't have an ftol arg, so I'm going to ignore it") - if self.gtol is not None: - opt_dict['pgtol'] = self.gtol - - opt_result = optimize.fmin_bfgs(f, self.x_init, fp, disp=self.messages, - maxiter=self.max_iters, full_output=True, **opt_dict) - self.x_opt = opt_result[0] - self.f_opt = f_fp(self.x_opt)[0] - self.funct_eval = opt_result[4] - self.status = rcstrings[opt_result[6]] - -class opt_simplex(Optimizer): - def __init__(self, *args, **kwargs): - Optimizer.__init__(self, *args, **kwargs) - self.opt_name = "Nelder-Mead simplex routine (via Scipy)" - - def opt(self, f_fp=None, f=None, fp=None): - """ - The simplex optimizer does not require gradients. - """ - - statuses = ['Converged', 'Maximum number of function evaluations made', 'Maximum number of iterations reached'] - - opt_dict = {} - if self.xtol is not None: - opt_dict['xtol'] = self.xtol - if self.ftol is not None: - opt_dict['ftol'] = self.ftol - if self.gtol is not None: - print("WARNING: simplex doesn't have an gtol arg, so I'm going to ignore it") - - opt_result = optimize.fmin(f, self.x_init, (), disp=self.messages, - maxfun=self.max_f_eval, full_output=True, **opt_dict) - - self.x_opt = opt_result[0] - self.f_opt = opt_result[1] - self.funct_eval = opt_result[3] - self.status = statuses[opt_result[4]] - self.trace = None - - -class opt_rasm(Optimizer): - def __init__(self, *args, **kwargs): - Optimizer.__init__(self, *args, **kwargs) - self.opt_name = "Rasmussen's Conjugate Gradient" - - def opt(self, f_fp=None, f=None, fp=None): - """ - Run Rasmussen's Conjugate Gradient optimizer - """ - - assert f_fp != None, "Rasmussen's minimizer requires f_fp" - statuses = ['Converged', 'Line search failed', 'Maximum number of f evaluations reached', - 'NaNs in optimization'] - - opt_dict = {} - if self.xtol is not None: - print("WARNING: minimize doesn't have an xtol arg, so I'm going to ignore it") - if self.ftol is not None: - print("WARNING: minimize doesn't have an ftol arg, so I'm going to ignore it") - if self.gtol is not None: - print("WARNING: minimize doesn't have an gtol arg, so I'm going to ignore it") - - opt_result = rasm.minimize(self.x_init, f_fp, (), messages=self.messages, - maxnumfuneval=self.max_f_eval) - self.x_opt = opt_result[0] - self.f_opt = opt_result[1][-1] - self.funct_eval = opt_result[2] - self.status = statuses[opt_result[3]] - - self.trace = opt_result[1] - -class opt_SCG(Optimizer): - def __init__(self, *args, **kwargs): - if 'max_f_eval' in kwargs: - warn("max_f_eval deprecated for SCG optimizer: use max_iters instead!\nIgnoring max_f_eval!", FutureWarning) - Optimizer.__init__(self, *args, **kwargs) - - self.opt_name = "Scaled Conjugate Gradients" - - def opt(self, f_fp=None, f=None, fp=None): - assert not f is None - assert not fp is None - - opt_result = SCG(f, fp, self.x_init, display=self.messages, - maxiters=self.max_iters, - max_f_eval=self.max_f_eval, - xtol=self.xtol, ftol=self.ftol, - gtol=self.gtol) - - self.x_opt = opt_result[0] - self.trace = opt_result[1] - self.f_opt = self.trace[-1] - self.funct_eval = opt_result[2] - self.status = opt_result[3] - -class Opt_Adadelta(Optimizer): - def __init__(self, step_rate=0.1, decay=0.9, momentum=0, *args, **kwargs): - Optimizer.__init__(self, *args, **kwargs) - self.opt_name = "Adadelta (climin)" - self.step_rate=step_rate - self.decay = decay - self.momentum = momentum - - def opt(self, f_fp=None, f=None, fp=None): - assert not fp is None - - import climin - - opt = climin.adadelta.Adadelta(self.x_init, fp, step_rate=self.step_rate, decay=self.decay, momentum=self.momentum) - - for info in opt: - if info['n_iter']>=self.max_iters: - self.x_opt = opt.wrt - self.status = 'maximum number of function evaluations exceeded ' - break - -def get_optimizer(f_min): - - optimizers = {'fmin_tnc': opt_tnc, - 'simplex': opt_simplex, - 'lbfgsb': opt_lbfgsb, - 'org-bfgs': opt_bfgs, - 'scg': opt_SCG, - 'adadelta':Opt_Adadelta} - - if rasm_available: - optimizers['rasmussen'] = opt_rasm - - for opt_name in optimizers.keys(): - if opt_name.lower().find(f_min.lower()) != -1: - return optimizers[opt_name] - - raise KeyError('No optimizer was found matching the name: %s' % f_min) diff --git a/GPy/plotting/gpy_plot/gp_plots.py b/GPy/plotting/gpy_plot/gp_plots.py index 353dc7fb..3e265842 100644 --- a/GPy/plotting/gpy_plot/gp_plots.py +++ b/GPy/plotting/gpy_plot/gp_plots.py @@ -319,9 +319,17 @@ def plot(self, plot_limits=None, fixed_inputs=None, :param {2d|3d} projection: plot in 2d or 3d? :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] 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, apply_link, np.linspace(2.5, 97.5, levels*2) if plot_density else (lower,upper), get_which_data_ycols(self, which_data_ycols), @@ -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 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, visible_dims, levels, samples, 0, lower, upper, plot_data, plot_inducing, From 3761d186f3debcad86bba9d43ef48977420fed2c Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Fri, 19 Feb 2016 17:15:29 +0000 Subject: [PATCH 24/40] [plotting] limits added --- GPy/plotting/gpy_plot/gp_plots.py | 4 ++-- GPy/plotting/gpy_plot/plot_util.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GPy/plotting/gpy_plot/gp_plots.py b/GPy/plotting/gpy_plot/gp_plots.py index 3e265842..7439bd9d 100644 --- a/GPy/plotting/gpy_plot/gp_plots.py +++ b/GPy/plotting/gpy_plot/gp_plots.py @@ -341,8 +341,8 @@ def plot(self, plot_limits=None, fixed_inputs=None, if hasattr(self, 'Z') and plot_inducing: plots.update(_plot_inducing(self, canvas, visible_dims, projection, 'Inducing')) if plot_data: - plots.update(_plot_data(self, canvas, which_data_rows, which_data_ycols, visible_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(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, free_dims, projection, "Data Error")) plots.update(_plot(self, canvas, plots, helper_data, helper_prediction, levels, plot_inducing, plot_density, projection)) if plot_raw and (samples_likelihood > 0): helper_prediction = helper_predict_with_model(self, helper_data[2], False, diff --git a/GPy/plotting/gpy_plot/plot_util.py b/GPy/plotting/gpy_plot/plot_util.py index a910cd6f..4e71a3bc 100644 --- a/GPy/plotting/gpy_plot/plot_util.py +++ b/GPy/plotting/gpy_plot/plot_util.py @@ -349,7 +349,7 @@ def x_frame1D(X,plot_limits=None,resolution=None): xmin,xmax = X.min(0),X.max(0) xmin, xmax = xmin-0.25*(xmax-xmin), xmax+0.25*(xmax-xmin) elif len(plot_limits) == 2: - xmin, xmax = plot_limits + xmin, xmax = map(np.atleast_1d, plot_limits) else: raise ValueError("Bad limits for plotting") From bfb0ecdcb4b232e3b389d82a9ecc63e739aa7184 Mon Sep 17 00:00:00 2001 From: Zhenwen Dai Date: Fri, 19 Feb 2016 17:59:50 +0000 Subject: [PATCH 25/40] add test case for hmc sampler --- GPy/testing/inference_tests.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/GPy/testing/inference_tests.py b/GPy/testing/inference_tests.py index 7a091589..267ce594 100644 --- a/GPy/testing/inference_tests.py +++ b/GPy/testing/inference_tests.py @@ -51,5 +51,20 @@ class InferenceXTestCase(unittest.TestCase): 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__": unittest.main() From 2c1064b95140828d0dba869e762f2d4272fa5783 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Wed, 24 Feb 2016 13:11:53 +0000 Subject: [PATCH 26/40] [matplotlib_dep] added the baseplots utility for backcompatibility --- GPy/plotting/matplot_dep/base_plots.py | 265 +++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 GPy/plotting/matplot_dep/base_plots.py diff --git a/GPy/plotting/matplot_dep/base_plots.py b/GPy/plotting/matplot_dep/base_plots.py new file mode 100644 index 00000000..d9910f59 --- /dev/null +++ b/GPy/plotting/matplot_dep/base_plots.py @@ -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 From 6f28edafcd82c57933d611aa1005005d5ddc6aa2 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Wed, 24 Feb 2016 13:13:09 +0000 Subject: [PATCH 27/40] [matplotlib_dep] added the baseplots utility for backcompatibility --- GPy/plotting/matplot_dep/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPy/plotting/matplot_dep/__init__.py b/GPy/plotting/matplot_dep/__init__.py index e9d2395d..d163519b 100644 --- a/GPy/plotting/matplot_dep/__init__.py +++ b/GPy/plotting/matplot_dep/__init__.py @@ -18,4 +18,4 @@ from .util import align_subplot_array, align_subplots, fewerXticks, removeRightTicks, removeUpperTicks -from . import controllers \ No newline at end of file +from . import controllers, base_plots \ No newline at end of file From 7d7399f846e7982511a1dd02f8ae772ff4e880be Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Wed, 24 Feb 2016 13:54:20 +0000 Subject: [PATCH 28/40] [gp_plots] transposed plotting of 2d contours --- GPy/plotting/gpy_plot/gp_plots.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPy/plotting/gpy_plot/gp_plots.py b/GPy/plotting/gpy_plot/gp_plots.py index 7439bd9d..eb252c0f 100644 --- a/GPy/plotting/gpy_plot/gp_plots.py +++ b/GPy/plotting/gpy_plot/gp_plots.py @@ -91,7 +91,7 @@ def _plot_mean(self, canvas, helper_data, helper_prediction, if projection == '2d': update_not_existing_kwargs(kwargs, pl().defaults.meanplot_2d) # @UndefinedVariable plots = dict(gpmean=[pl().contour(canvas, x[:,0], y[0,:], - mu.reshape(resolution, resolution), + mu.reshape(resolution, resolution).T, levels=levels, label=label, **kwargs)]) elif projection == '3d': update_not_existing_kwargs(kwargs, pl().defaults.meanplot_3d) # @UndefinedVariable From c1ed2fe8da97f190e1d70e442c01ee9da3a43f56 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Wed, 24 Feb 2016 14:20:35 +0000 Subject: [PATCH 29/40] =?UTF-8?q?Bump=20version:=200.9.6=20=E2=86=92=200.9?= =?UTF-8?q?.7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GPy/__version__.py | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GPy/__version__.py b/GPy/__version__.py index 50533e30..f5b77301 100644 --- a/GPy/__version__.py +++ b/GPy/__version__.py @@ -1 +1 @@ -__version__ = "0.9.6" +__version__ = "0.9.7" diff --git a/setup.cfg b/setup.cfg index 3a2581bd..188a6bab 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.9.6 +current_version = 0.9.7 tag = True commit = True From 01a7f85c9eb3e6c1736fa6fff49d8d9b0784c661 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Thu, 25 Feb 2016 08:39:21 +0000 Subject: [PATCH 30/40] [Poly] added bias and scale --- GPy/kern/src/poly.py | 35 ++++++++++++++++++++++++++--------- GPy/testing/kernel_tests.py | 5 +++++ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/GPy/kern/src/poly.py b/GPy/kern/src/poly.py index 216e3a00..a3dbfed5 100644 --- a/GPy/kern/src/poly.py +++ b/GPy/kern/src/poly.py @@ -5,32 +5,49 @@ import numpy as np from .kern import Kern from ...core.parameterization import Param from paramz.transformations import Logexp +from paramz.caching import Cache_this class Poly(Kern): """ 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) 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 - 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: - return np.dot(X, X.T) + dot_prod = np.dot(X, X.T) 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): - 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): - 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): raise NotImplementedError diff --git a/GPy/testing/kernel_tests.py b/GPy/testing/kernel_tests.py index bae7b2e4..5278c8b2 100644 --- a/GPy/testing/kernel_tests.py +++ b/GPy/testing/kernel_tests.py @@ -324,6 +324,11 @@ class KernelGradientTestsContinuous(unittest.TestCase): k.randomize() 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): k = GPy.kern.StdPeriodic(self.D, self.D-1) k.randomize() From c18d9dac84b9ef7b45ca4e1753645292d5d29324 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Thu, 25 Feb 2016 08:40:05 +0000 Subject: [PATCH 31/40] [Poly] added bias and scale --- GPy/kern/src/poly.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPy/kern/src/poly.py b/GPy/kern/src/poly.py index a3dbfed5..8aa33b1a 100644 --- a/GPy/kern/src/poly.py +++ b/GPy/kern/src/poly.py @@ -27,7 +27,7 @@ class Poly(Kern): _, _, B = self._AB(X, X2) return B * self.variance - #@Cache_this(limit=2) + @Cache_this(limit=2) def _AB(self, X, X2=None): if X2 is None: dot_prod = np.dot(X, X.T) From b957bb2016673eaf862de7cf002553ec1fbc4a12 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Thu, 25 Feb 2016 09:11:11 +0000 Subject: [PATCH 32/40] [travis] added retries for installing conda, as it seemed to fail on 404 errors --- .travis.yml | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 98806750..10e596da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,18 +21,18 @@ env: before_install: - export CONDA_CACHED=1 - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; - then export OS=Linux; - elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; + then export OS=Linux; + elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export OS=MacOSX; - brew install pandoc; - else - echo "OS not supported yet"; + 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; + - 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; @@ -43,7 +43,13 @@ before_install: - export PATH="$MINICONDA_INSTALL/bin:$PATH"; install: - - conda install --yes python=$PYTHON_VERSION numpy=1.9 scipy=0.16 nose pip six matplotlib sphinx; + - n=0 + until [ $n -ge 5 ] + do # Retry 5 times, as weird 404 errors seem to popup... + conda install --yes python=$PYTHON_VERSION numpy=1.9 scipy=0.16 nose pip six matplotlib sphinx && break + n=$[$n+1] + sleep 15 + done - pip install codecov - pip install pypandoc - python setup.py develop @@ -60,16 +66,16 @@ before_deploy: - sphinx-apidoc -o source/ ../GPy - make html - cd ../ - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export DIST='sdist'; - elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; + elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export DIST='bdist_wheel'; fi; deploy: provider: pypi user: maxz - password: + password: secure: "vMEOlP7DQhFJ7hQAKtKC5hrJXFl5BkUt4nXdosWWiw//Kg8E+PPLg88XPI2gqIosir9wwgtbSBBbbwCxkM6uxRNMpoNR8Ixyv9fmSXp4rLl7bbBY768W7IRXKIBjpuEy2brQjoT+CwDDSzUkckHvuUjJDNRvUv8ab4P/qYO1LG4=" on: tags: false From e73fcac5213a75fd981d28efd518d3dcc80ed14f Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Fri, 26 Feb 2016 09:43:28 +0000 Subject: [PATCH 33/40] [latent plots] legend was always plotted --- GPy/plotting/gpy_plot/latent_plots.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPy/plotting/gpy_plot/latent_plots.py b/GPy/plotting/gpy_plot/latent_plots.py index ed12ad9a..40ad0251 100644 --- a/GPy/plotting/gpy_plot/latent_plots.py +++ b/GPy/plotting/gpy_plot/latent_plots.py @@ -188,7 +188,7 @@ 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) 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) - if (labels is not None): + if (labels is not None) and legend: legend = find_best_layout_for_subplots(len(np.unique(labels)))[1] else: labels = np.ones(self.num_data) @@ -254,7 +254,7 @@ def plot_latent(self, labels=None, which_indices=None, _, _, 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]), xlabel='latent dimension %i' % input_1, ylabel='latent dimension %i' % input_2, **imshow_kwargs) - if (labels is not None): + if (labels is not None) and legend: legend = find_best_layout_for_subplots(len(np.unique(labels)))[1] else: labels = np.ones(self.num_data) From 218616154cb81e609f1611677951de9a6949d39b Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Fri, 26 Feb 2016 09:51:58 +0000 Subject: [PATCH 34/40] [latent plots] legend was always plotted --- GPy/plotting/gpy_plot/latent_plots.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPy/plotting/gpy_plot/latent_plots.py b/GPy/plotting/gpy_plot/latent_plots.py index 40ad0251..92035d65 100644 --- a/GPy/plotting/gpy_plot/latent_plots.py +++ b/GPy/plotting/gpy_plot/latent_plots.py @@ -256,7 +256,7 @@ def plot_latent(self, labels=None, which_indices=None, xlabel='latent dimension %i' % input_1, ylabel='latent dimension %i' % input_2, **imshow_kwargs) if (labels is not None) and legend: legend = find_best_layout_for_subplots(len(np.unique(labels)))[1] - else: + elif legend: 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 {}) From 6d34cf3ad17d000ed0386dca74a2e5bb084c20de Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Fri, 26 Feb 2016 09:54:41 +0000 Subject: [PATCH 35/40] [latent plots] legend was always plotted --- GPy/plotting/gpy_plot/latent_plots.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/GPy/plotting/gpy_plot/latent_plots.py b/GPy/plotting/gpy_plot/latent_plots.py index 92035d65..54982fc5 100644 --- a/GPy/plotting/gpy_plot/latent_plots.py +++ b/GPy/plotting/gpy_plot/latent_plots.py @@ -188,11 +188,12 @@ 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) 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) - if (labels is not None) and legend: - legend = find_best_layout_for_subplots(len(np.unique(labels)))[1] - else: - labels = np.ones(self.num_data) - legend = False + if legend: + if (labels is not None): + legend = find_best_layout_for_subplots(len(np.unique(labels)))[1] + else: + 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 {}) view = _plot_magnification(self, canvas, which_indices, Xgrid, xmin, xmax, resolution, updates, mean, covariance, kern, **imshow_kwargs) retval = pl().add_to_canvas(canvas, dict(scatter=scatters, imshow=view), @@ -254,11 +255,12 @@ def plot_latent(self, labels=None, which_indices=None, _, _, 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]), xlabel='latent dimension %i' % input_1, ylabel='latent dimension %i' % input_2, **imshow_kwargs) - if (labels is not None) and legend: - legend = find_best_layout_for_subplots(len(np.unique(labels)))[1] - elif legend: - labels = np.ones(self.num_data) - legend = False + if legend: + if (labels is not None): + legend = find_best_layout_for_subplots(len(np.unique(labels)))[1] + else: + 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 {}) 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) From 9c2eac6e1e7916c0b90d41269ec3ee3d7c2b121f Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Fri, 26 Feb 2016 12:01:00 +0000 Subject: [PATCH 36/40] [latent plots] legend was always plotted --- GPy/plotting/gpy_plot/latent_plots.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/GPy/plotting/gpy_plot/latent_plots.py b/GPy/plotting/gpy_plot/latent_plots.py index 54982fc5..df5e239a 100644 --- a/GPy/plotting/gpy_plot/latent_plots.py +++ b/GPy/plotting/gpy_plot/latent_plots.py @@ -163,7 +163,8 @@ def plot_magnification(self, labels=None, which_indices=None, updates=False, mean=True, covariance=True, 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 density of the GP as a gray scale. @@ -188,18 +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) 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) + plots = {} if legend: if (labels is not None): legend = find_best_layout_for_subplots(len(np.unique(labels)))[1] else: 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 {}) - view = _plot_magnification(self, canvas, which_indices, Xgrid, xmin, xmax, resolution, updates, mean, covariance, kern, **imshow_kwargs) - 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, ) - _wait_for_updates(view, updates) + _wait_for_updates(plots['view'], updates) return retval From 3dd3b1dd6ad54db32416b551594cc66041989b02 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Fri, 26 Feb 2016 12:01:57 +0000 Subject: [PATCH 37/40] [latent plots] legend was always plotted --- GPy/plotting/gpy_plot/latent_plots.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPy/plotting/gpy_plot/latent_plots.py b/GPy/plotting/gpy_plot/latent_plots.py index df5e239a..ef8f3072 100644 --- a/GPy/plotting/gpy_plot/latent_plots.py +++ b/GPy/plotting/gpy_plot/latent_plots.py @@ -190,7 +190,7 @@ def plot_magnification(self, labels=None, which_indices=None, 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) plots = {} - if legend: + if legend and plot_scatter: if (labels is not None): legend = find_best_layout_for_subplots(len(np.unique(labels)))[1] else: From 80aea4412ec32a0a5142ac5e46f6e0ec19d03ed9 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Mon, 29 Feb 2016 14:33:33 +0000 Subject: [PATCH 38/40] [svgp] python 3.x fix for next --- GPy/core/svgp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPy/core/svgp.py b/GPy/core/svgp.py index a678a1fd..916952f2 100644 --- a/GPy/core/svgp.py +++ b/GPy/core/svgp.py @@ -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 """ - i = self.slicer.next() + i = next(self.slicer) return self.X_all[i], self.Y_all[i] def stochastic_grad(self, parameters): From 2d80f9c096e93846328eda3c5160ed40501e1e5f Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Mon, 29 Feb 2016 14:47:24 +0000 Subject: [PATCH 39/40] [travis_scripts] loading scripts from github repo --- .travis.yml | 40 +++++++++------------------------------- 1 file changed, 9 insertions(+), 31 deletions(-) diff --git a/.travis.yml b/.travis.yml index 10e596da..0e9efae1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,39 +20,17 @@ env: - PYTHON_VERSION=3.5 before_install: - - export CONDA_CACHED=1 - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; - then export OS=Linux; - elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; - 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"; +- wget https://github.com/mzwiessele/travis_scripts/raw/master/download_miniconda.sh +- wget https://github.com/mzwiessele/travis_scripts/raw/master/install_retry.sh +- source download_miniconda.sh +- echo $PATH install: - - n=0 - until [ $n -ge 5 ] - do # Retry 5 times, as weird 404 errors seem to popup... - conda install --yes python=$PYTHON_VERSION numpy=1.9 scipy=0.16 nose pip six matplotlib sphinx && break - n=$[$n+1] - sleep 15 - done - - pip install codecov - - pip install pypandoc - - python setup.py develop +- echo $PATH +- source install_retry.sh +- pip install codecov +- pip install pypandoc +- python setup.py develop script: - coverage run travis_tests.py From 885d3722cce0d7ee492f0d0d0f8f035954af70f6 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Tue, 1 Mar 2016 10:02:02 +0000 Subject: [PATCH 40/40] [mrd] plot_scales and plot_latent added --- GPy/examples/dimensionality_reduction.py | 4 +- GPy/installation.cfg | 2 +- GPy/models/mrd.py | 94 +++++---------- GPy/plotting/__init__.py | 116 ++++++++++--------- GPy/plotting/gpy_plot/kernel_plots.py | 12 +- GPy/plotting/matplot_dep/plot_definitions.py | 17 +-- GPy/plotting/matplot_dep/ssgplvm.py | 6 +- GPy/testing/__init__.py | 9 +- 8 files changed, 112 insertions(+), 148 deletions(-) diff --git a/GPy/examples/dimensionality_reduction.py b/GPy/examples/dimensionality_reduction.py index 024b12ee..ce1c89e8 100644 --- a/GPy/examples/dimensionality_reduction.py +++ b/GPy/examples/dimensionality_reduction.py @@ -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 _, _, 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['.*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 _, _, 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 = [] for Y in Ylist: diff --git a/GPy/installation.cfg b/GPy/installation.cfg index 8458a86b..841bf608 100644 --- a/GPy/installation.cfg +++ b/GPy/installation.cfg @@ -15,4 +15,4 @@ # [plotting] -# library = matplotlib # plotly +# library = matplotlib # plotly, none diff --git a/GPy/models/mrd.py b/GPy/models/mrd.py index be28d1a5..4e7f2f3b 100644 --- a/GPy/models/mrd.py +++ b/GPy/models/mrd.py @@ -5,14 +5,14 @@ import numpy as np import itertools, logging from ..kern import Kern -from GPy.core.parameterization.variational import NormalPrior +from ..core.parameterization.variational import NormalPrior from ..core.parameterization import Param from paramz import ObsAr from ..inference.latent_function_inference.var_dtc import VarDTC from ..inference.latent_function_inference import InferenceMethodList from ..likelihoods import Gaussian from ..util.initialization import initialize_latent -from GPy.models.bayesian_gplvm_minibatch import BayesianGPLVMMiniBatch +from ..models.bayesian_gplvm_minibatch import BayesianGPLVMMiniBatch class MRD(BayesianGPLVMMiniBatch): """ @@ -215,40 +215,6 @@ class MRD(BayesianGPLVMMiniBatch): Z = np.random.randn(self.num_inducing, self.input_dim) * X.var() 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): """ Prediction for data set Yindex[default=0]. @@ -270,59 +236,53 @@ class MRD(BayesianGPLVMMiniBatch): # sharex=sharex, sharey=sharey) # 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): """ - - TODO: Explain other parameters + Plot input sensitivity for all datasets, to see which input dimensions are + significant for which dataset. :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: 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): - #ax.set_ylim([0,ymax]) - return g.kern.plot_ARD(ax=ax, title=titles[i], *args, **kwargs) - fig = self._handle_plotting(fignum, ax, plotf, sharex=sharex, sharey=sharey) - return fig + + M = len(self.bgplvms) + fig = pl().figure(rows=1, cols=M, **fig_kwargs) + plots = {} + for c in range(M): + 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, - resolution=50, ax=None, marker='o', s=40, - fignum=None, plot_inducing=True, legend=True, + resolution=60, legend=True, 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 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'. """ - import sys - 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 + from ..plotting.gpy_plot.latent_plots import plot_latent + if "Yindex" not in predict_kwargs: predict_kwargs['Yindex'] = 0 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.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): state = super(MRD, self).__getstate__() diff --git a/GPy/plotting/__init__.py b/GPy/plotting/__init__.py index c46d5281..4b833fe3 100644 --- a/GPy/plotting/__init__.py +++ b/GPy/plotting/__init__.py @@ -25,18 +25,66 @@ def change_plotting_library(lib): current_lib[0] = PlotlyPlots() if lib == 'none': current_lib[0] = None + inject_plotting() #=========================================================================== except (ImportError, NameError): config.set('plotting', 'library', 'none') + raise import warnings 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 -try: - lib = config.get('plotting', 'library') - change_plotting_library(lib) -except NoOptionError: - print("No plotting library was specified in config file. \n{}".format(error_suggestion)) +def inject_plotting(): + if current_lib[0] is not None: + # Inject the plots into classes here: + + # Already converted to new style: + 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(): if current_lib[0] is None: @@ -53,54 +101,10 @@ def show(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 . 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! +from ..util.config import config, NoOptionError +try: + lib = config.get('plotting', 'library') + change_plotting_library(lib) +except NoOptionError: + print("No plotting library was specified in config file. \n{}".format(error_suggestion)) \ No newline at end of file diff --git a/GPy/plotting/gpy_plot/kernel_plots.py b/GPy/plotting/gpy_plot/kernel_plots.py index 492754b2..2255a665 100644 --- a/GPy/plotting/gpy_plot/kernel_plots.py +++ b/GPy/plotting/gpy_plot/kernel_plots.py @@ -33,7 +33,7 @@ from .. import Tango from .plot_util import update_not_existing_kwargs, helper_for_plot_data 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 @@ -62,7 +62,11 @@ def plot_ARD(kernel, filtering=None, legend=False, **kwargs): bars = [] 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]): if parts[i].name in filtering: c = Tango.nextMedium() @@ -96,7 +100,7 @@ def plot_covariance(kernel, x=None, label=None, """ X = np.ones((2, kernel._effective_input_dim)) * [[-3], [3]] _, free_dims, Xgrid, xx, yy, _, _, resolution = helper_for_plot_data(kernel, X, plot_limits, visible_dims, None, resolution) - + from numbers import Number if x is None: from ...kern.src.stationary import Stationary @@ -104,7 +108,7 @@ def plot_covariance(kernel, x=None, label=None, elif isinstance(x, Number): x = np.ones((1, kernel._effective_input_dim))*x K = kernel.K(Xgrid, x) - + if projection == '3d': xlabel = 'X[:,0]' ylabel = 'X[:,1]' diff --git a/GPy/plotting/matplot_dep/plot_definitions.py b/GPy/plotting/matplot_dep/plot_definitions.py index 9eb9efb0..52100ea3 100644 --- a/GPy/plotting/matplot_dep/plot_definitions.py +++ b/GPy/plotting/matplot_dep/plot_definitions.py @@ -42,10 +42,11 @@ class MatplotlibPlots(AbstractPlottingLibrary): super(MatplotlibPlots, self).__init__() self._defaults = defaults.__dict__ - def figure(self, rows=1, cols=1, **kwargs): - fig = plt.figure(**kwargs) + def figure(self, rows=1, cols=1, gridspec_kwargs={}, tight_layout=True, **kwargs): + fig = plt.figure(tight_layout=tight_layout, **kwargs) fig.rows = rows fig.cols = cols + fig.gridspec = plt.GridSpec(rows, cols, **gridspec_kwargs) return fig 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): @@ -56,7 +57,9 @@ class MatplotlibPlots(AbstractPlottingLibrary): if 'ax' in kwargs: ax = kwargs.pop('ax') 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')) elif 'num' in kwargs: fig = self.figure(num=kwargs.pop('num')) @@ -66,7 +69,7 @@ class MatplotlibPlots(AbstractPlottingLibrary): fig = self.figure() #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 ylim is not None: ax.set_ylim(ylim) @@ -79,7 +82,7 @@ class MatplotlibPlots(AbstractPlottingLibrary): return ax, 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) if legend is True: ax.legend(*ax.get_legend_handles_labels()) @@ -89,9 +92,7 @@ class MatplotlibPlots(AbstractPlottingLibrary): if title is not None: ax.figure.suptitle(title) return ax - def show_canvas(self, ax, tight_layout=False, **kwargs): - if tight_layout: - ax.figure.tight_layout() + def show_canvas(self, ax): ax.figure.canvas.draw() return ax.figure diff --git a/GPy/plotting/matplot_dep/ssgplvm.py b/GPy/plotting/matplot_dep/ssgplvm.py index b741bc5d..0ed8a043 100644 --- a/GPy/plotting/matplot_dep/ssgplvm.py +++ b/GPy/plotting/matplot_dep/ssgplvm.py @@ -13,16 +13,16 @@ class SSGPLVM_plot(object): self.model = model self.imgsize= imgsize assert model.Y.shape[1] == imgsize[0]*imgsize[1] - + def plot_inducing(self): fig1 = pylab.figure() mean = self.model.posterior.mean arr = mean.reshape(*(mean.shape[0],self.imgsize[1],self.imgsize[0])) plot_2D_images(fig1, arr) fig1.gca().set_title('The mean of inducing points') - + fig2 = pylab.figure() covar = self.model.posterior.covariance plot_2D_images(fig2, covar) fig2.gca().set_title('The variance of inducing points') - + diff --git a/GPy/testing/__init__.py b/GPy/testing/__init__.py index 2e64d90e..abad1fa3 100644 --- a/GPy/testing/__init__.py +++ b/GPy/testing/__init__.py @@ -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) -""" - -MaxZ - -""" import unittest import sys def deepTest(reason): if reason: 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")