def _build_conditional(self, Xnew, pred_noise, diag, X, Xu, y, sigma, cov_total, mean_total): sigma2 = at.square(sigma) Kuu = cov_total(Xu) Kuf = cov_total(Xu, X) Luu = cholesky(stabilize(Kuu)) A = solve_lower(Luu, Kuf) Qffd = at.sum(A * A, 0) if self.approx == "FITC": Kffd = cov_total(X, diag=True) Lamd = at.clip(Kffd - Qffd, 0.0, np.inf) + sigma2 else: # VFE or DTC Lamd = at.ones_like(Qffd) * sigma2 A_l = A / Lamd L_B = cholesky(at.eye(Xu.shape[0]) + at.dot(A_l, at.transpose(A))) r = y - mean_total(X) r_l = r / Lamd c = solve_lower(L_B, at.dot(A, r_l)) Kus = self.cov_func(Xu, Xnew) As = solve_lower(Luu, Kus) mu = self.mean_func(Xnew) + at.dot(at.transpose(As), solve_upper(at.transpose(L_B), c)) C = solve_lower(L_B, As) if diag: Kss = self.cov_func(Xnew, diag=True) var = Kss - at.sum(at.square(As), 0) + at.sum(at.square(C), 0) if pred_noise: var += sigma2 return mu, var else: cov = self.cov_func(Xnew) - at.dot(at.transpose(As), As) + at.dot( at.transpose(C), C) if pred_noise: cov += sigma2 * at.identity_like(cov) return mu, cov if pred_noise else stabilize(cov)
def square_dist(self, X, Xs=None): X2 = aet.sum(aet.square(X), 1) if Xs is None: sqd = -2.0 * aet.dot(X, aet.transpose(X)) + ( aet.reshape(X2, (-1, 1)) + aet.reshape(X2, (1, -1))) else: Xs2 = aet.sum(aet.square(Xs), 1) sqd = -2.0 * aet.dot(X, aet.transpose(Xs)) + ( aet.reshape(X2, (-1, 1)) + aet.reshape(Xs2, (1, -1))) return aet.clip(sqd, 0.0, np.inf)
def full(self, X, Xs=None): X, Xs = self._slice(X, Xs) rx = self.lfunc(at.as_tensor_variable(X), self.args) if Xs is None: rz = self.lfunc(at.as_tensor_variable(X), self.args) r2 = self.square_dist(X, X) else: rz = self.lfunc(at.as_tensor_variable(Xs), self.args) r2 = self.square_dist(X, Xs) rx2 = at.reshape(at.square(rx), (-1, 1)) rz2 = at.reshape(at.square(rz), (1, -1)) return at.sqrt((2.0 * at.outer(rx, rz)) / (rx2 + rz2)) * at.exp(-1.0 * r2 / (rx2 + rz2))
def square_dist(self, X, Xs): X = at.mul(X, 1.0 / self.ls) X2 = at.sum(at.square(X), 1) if Xs is None: sqd = -2.0 * at.dot(X, at.transpose(X)) + (at.reshape(X2, (-1, 1)) + at.reshape(X2, (1, -1))) else: Xs = at.mul(Xs, 1.0 / self.ls) Xs2 = at.sum(at.square(Xs), 1) sqd = -2.0 * at.dot(X, at.transpose(Xs)) + ( at.reshape(X2, (-1, 1)) + at.reshape(Xs2, (1, -1))) return at.clip(sqd, 0.0, np.inf)
def _build_marginal_likelihood_logp(self, y, X, Xu, sigma): sigma2 = at.square(sigma) Kuu = self.cov_func(Xu) Kuf = self.cov_func(Xu, X) Luu = cholesky(stabilize(Kuu)) A = solve_lower(Luu, Kuf) Qffd = at.sum(A * A, 0) if self.approx == "FITC": Kffd = self.cov_func(X, diag=True) Lamd = at.clip(Kffd - Qffd, 0.0, np.inf) + sigma2 trace = 0.0 elif self.approx == "VFE": Lamd = at.ones_like(Qffd) * sigma2 trace = (1.0 / (2.0 * sigma2)) * (at.sum(self.cov_func(X, diag=True)) - at.sum(at.sum(A * A, 0))) else: # DTC Lamd = at.ones_like(Qffd) * sigma2 trace = 0.0 A_l = A / Lamd L_B = cholesky(at.eye(Xu.shape[0]) + at.dot(A_l, at.transpose(A))) r = y - self.mean_func(X) r_l = r / Lamd c = solve_lower(L_B, at.dot(A, r_l)) constant = 0.5 * X.shape[0] * at.log(2.0 * np.pi) logdet = 0.5 * at.sum(at.log(Lamd)) + at.sum(at.log(at.diag(L_B))) quadratic = 0.5 * (at.dot(r, r_l) - at.dot(c, c)) return -1.0 * (constant + logdet + quadratic + trace)
def full(self, X, Xs=None): X, Xs = self._slice(X, Xs) if Xs is None: Xs = X f1 = X.dimshuffle(0, "x", 1) f2 = Xs.dimshuffle("x", 0, 1) r = np.pi * (f1 - f2) / self.period r = at.sum(at.square(at.sin(r) / self.ls), 2) return at.exp(-0.5 * r)
def _build_conditional(self, Xnew, pred_noise, diag, X, y, noise, cov_total, mean_total): Kxx = cov_total(X) Kxs = self.cov_func(X, Xnew) Knx = noise(X) rxx = y - mean_total(X) L = cholesky(stabilize(Kxx) + Knx) A = solve_lower(L, Kxs) v = solve_lower(L, rxx) mu = self.mean_func(Xnew) + at.dot(at.transpose(A), v) if diag: Kss = self.cov_func(Xnew, diag=True) var = Kss - at.sum(at.square(A), 0) if pred_noise: var += noise(Xnew, diag=True) return mu, var else: Kss = self.cov_func(Xnew) cov = Kss - at.dot(at.transpose(A), A) if pred_noise: cov += noise(Xnew) return mu, cov if pred_noise else stabilize(cov)
def _build_conditional(self, Xnew, pred_noise, diag): Xs, y, sigma = self.Xs, self.y, self.sigma # Old points X = cartesian(*Xs) delta = y - self.mean_func(X) Kns = [f(x) for f, x in zip(self.cov_funcs, Xs)] eigs_sep, Qs = zip(*map(eigh, Kns)) # Unzip QTs = list(map(at.transpose, Qs)) eigs = kron_diag(*eigs_sep) # Combine separate eigs if sigma is not None: eigs += sigma**2 # New points Km = self.cov_func(Xnew, diag=diag) Knm = self.cov_func(X, Xnew) Kmn = Knm.T # Build conditional mu alpha = kron_dot(QTs, delta) alpha = alpha / eigs[:, None] alpha = kron_dot(Qs, alpha) mu = at.dot(Kmn, alpha).ravel() + self.mean_func(Xnew) # Build conditional cov A = kron_dot(QTs, Knm) A = A / at.sqrt(eigs[:, None]) if diag: Asq = at.sum(at.square(A), 0) cov = Km - Asq if pred_noise: cov += sigma else: Asq = at.dot(A.T, A) cov = Km - Asq if pred_noise: cov += sigma * at.identity_like(cov) return mu, cov
def log_diff_normal_cdf(mu, sigma, x, y): """ Compute :math:`\\log(\\Phi(\frac{x - \\mu}{\\sigma}) - \\Phi(\frac{y - \\mu}{\\sigma}))` safely in log space. Parameters ---------- mu: float mean sigma: float std x: float y: float must be strictly less than x. Returns ------- log (\\Phi(x) - \\Phi(y)) """ x = (x - mu) / sigma / aet.sqrt(2.0) y = (y - mu) / sigma / aet.sqrt(2.0) # To stabilize the computation, consider these three regions: # 1) x > y > 0 => Use erf(x) = 1 - e^{-x^2} erfcx(x) and erf(y) =1 - e^{-y^2} erfcx(y) # 2) 0 > x > y => Use erf(x) = e^{-x^2} erfcx(-x) and erf(y) = e^{-y^2} erfcx(-y) # 3) x > 0 > y => Naive formula log( (erf(x) - erf(y)) / 2 ) works fine. return aet.log(0.5) + aet.switch( aet.gt(y, 0), -aet.square(y) + aet.log( aet.erfcx(y) - aet.exp(aet.square(y) - aet.square(x)) * aet.erfcx(x)), aet.switch( aet.lt(x, 0), # 0 > x > y -aet.square(x) + aet.log( aet.erfcx(-x) - aet.exp(aet.square(x) - aet.square(y)) * aet.erfcx(-y)), aet.log(aet.erf(x) - aet.erf(y)), # x >0 > y ), )
def diag(self, X): X, _ = self._slice(X, None) cov_diag = self.cov_func(X, diag=True) scf_diag = at.square(at.flatten(self.scaling_func(X, self.args))) return cov_diag * scf_diag
def diag(self, X): X, Xc, _ = self._common(X, None) return at.sum(at.square(Xc), 1)
def full(self, X, Xs=None): X, Xs = self._slice(X, Xs) r = self.euclidean_dist(X, Xs) return (1.0 + np.sqrt(5.0) * r + 5.0 / 3.0 * at.square(r)) * at.exp( -1.0 * np.sqrt(5.0) * r)
def diag(self, X): return at.alloc(at.square(self.sigma), X.shape[0])
def volatility_update(x, vol, w, a, b): return at.sqrt(w + a * at.square(x) + b * at.square(vol))