def KL_Wishart(nu_h, W_h, nu, W): ''' :param nu_h/ nu: float :param W_h/ W: arr(D, D) :return val: float ''' from numpy import newaxis data_dim = len(W[0]) val = 0 if W.ndim == 2: invW = inv(W) invW_wh = dot(invW, W_h) val += -0.5 * nu * logdet(invW_wh[newaxis, :, :]) val += 0.5 * nu_h * (trace(invW_wh) - data_dim) for d in range(1, data_dim + 1): val += gammaln((nu + 1 - d) / 2.0) - gammaln((nu_h + 1 - d) / 2.0) val += (nu_h - nu) * digamma((nu_h + 1.0 - d) / 2.0) / 2.0 else: invW = inv(W.transpose(2, 0, 1)).transpose(1, 2, 0) invW_Wh = einsum('dek,efk->kdf', invW, W_h) val += -0.5 * nu * logdet(invW_Wh) val += 0.5 * nu_h * (trace(invW_Wh) - data_dim) nuh_nu = nu_h - nu for d in range(1, data_dim + 1): lngam_nuh_d_2 = gammaln((nu_h + 1.0 - d) / 2.0) lngam_nu_d_2 = gammaln(nu + 1.0 - d / 2.0) dig_nuh_d_2 = digamma((nu_h + 1.0 - d) / 2.0) val += lngam_nu_d_2 - lngam_nuh_d_2 val += nuh_nu * dig_nuh_d_2 return val
def calc_inv(self, src): if src.ndim == 2: dst = inv(src) elif src.ndim == 3: dst = inv(src.transpose(2, 0, 1)).transpose(1, 2, 0) else: logger.error('ndim %d is not supported' % src.ndim) dst = None return dst
def _calc_inv(self, src): if src.ndim == 1: dst = 1.0 / src elif src.ndim == 2: dst = inv(src) elif src.ndim == 3: dst = inv(src.transpose(2, 0, 1)).transpose(1, 2, 0) elif src.ndim == 4: dst = inv(src.transpose(2, 3, 0, 1)).transpose(2, 3, 0, 1) else: self._log_error_not_supported() dst = None return dst
def KL_Gauss(mu_h, sig_h, mu, sig): ''' :param mu_h: arr(data_dim) :param sig_h: arr(data_dim, data_dim) :param mu: arr(data_dim) :param sig: arr(data_dim, data_dim) :return val: float (mu_h - mu)T * sig^{-1} * (mu_h - mu) + Tr(inv_sig * sig_h) - data_dim + log(|sig|) - log(|sig_h|) ''' data_dim = len(mu_h) inv_sig = inv(sig) mu_h_mu = mu_h - mu val = 0.5 * (einsum('d,de,e->', mu_h_mu, inv_sig, mu_h_mu) + trace( dot(inv_sig, sig_h)) - data_dim + logdet(sig) - logdet(sig_h)) return val
def update(self, Y, z, r): ''' lamb.update(Y, z, r) Y: array(data_dim, data_len) r.post.expt: <R> z.post.expt2: <ZZ> ''' # --- prec (inv(cov)) rzz = einsum('ddk,ljt->ljdk', r.post.expt, z.expt2) prec = self.prior.prec + rzz # --- cov cov = inv(prec.transpose(2, 3, 1, 0)).transpose(2, 3, 0, 1) # --- mean yz = einsum('dt,lt->ld', Y, z.mu) ryz = einsum('ddk,ld->ldk', r.post.expt, yz) pm_ryz = self.prior.expt_prec_mu + ryz mean = einsum('ljdk,jdk->ldk', cov, pm_ryz) self.post.set_params(mu=mean, cov=cov, prec=prec)
def sample_mu(self, data_len=1, R=None): ''' mu: (data_len, data_dim, n_states) ''' if R is None: R = self.sample_R()[0] mu = zeros((data_len, self.data_dim, self.n_states)) for k in range(self.n_states): # cov = inv(self.beta[k] * R[:, :, k]) cov = inv(R[:, :, k]) try: mu[:, :, k] = mvnrnd(self.mu[:, k], cov, size=data_len) except RuntimeWarning as e: logger.warn('%s %d. not sampled' % (e, mu.shape[0])) mu[:, :, k] = self.mu[newaxis, :, k] except Exception as e: logger.error('%s %d. not sampled.' % (e, mu.shape[0])) mu[:, :, k] = self.mu[newaxis, :, k] return mu
def update(self, theta, Y): ''' z.update(Y) lamb.mu: <lamb> array(aug_dim, data_dim) lamb.post.expt2: <lamblambT> array(aug_dim, aug_dim, data_dim) r.post.expt: <R> array(data_dim) lamb.post.mu: <lamb> array(aug_dim, data_dim) ''' # -- prec rll = einsum('ddk,ljdk->lj', theta.r.post.expt, theta.lamb.post.expt2) self.prec = rll + self.prior.prec[:, :, 0] # --- cov self.cov = inv(self.prec) # --- mean lr = einsum('ldk,ddk->ld', theta.lamb.post.mu, theta.r.post.expt) lry = einsum('ld,dt->lt', lr, Y) lry_muz = lry + self.prior.expt_prec_mu[:, 0, newaxis] self.mu = einsum('lj,jt->lt', self.cov, lry_muz) self.expt2 = self.calc_expt2()
def Z(cls, fa_dim): ''' DefaultPriors().Z(fa_dim) @argvs fa_dim: dimention of factor analysis @output z_mean: np.array(aug_dim) z_cov: np.array(aug_dim, aug_dim) z_prc: np.array(aug_dim, aug_dim) ''' aug_dim = fa_dim + 1 # --- Z fa_dim = int(aug_dim - 1) eps = 1e-8 # eps = get_eps() # eps = get_eps() * 1e+10 z_mean = append(zeros(fa_dim), [1]) z_cov = eye(aug_dim) z_cov[-1, -1] = eps z_prc = inv(z_cov) return z_mean, z_cov, z_prc
def samples(self, data_len, by_posterior=True): ''' y, z, [lamb, prec, cov] = fa.samples(data_len, by_posterior=True) Returns y: np.array(data_dim, data_len). z: np.array(aug_dim, data_len). lamb: np.array(aug_dim, data_dim, n_states). prec: np.array(data_dim, data_dim, n_states). cov: np.array(data_dim, data_dim, n_states). * aug_dim = fa_dim + 1 * n_states = 1 ''' z = self.z.samples(data_len, by_posterior) # lamb, prec = self.theta.samples(1, by_posterior) lamb, prec = self.theta.expectations(1, by_posterior) y = zeros((self.data_dim, data_len)) mu = einsum('ld,lt->dt', lamb[:, :, 0], z) cov = inv(prec[:, :, 0]) for t in range(data_len): y[:, t] = mvnrnd(mu[:, t], cov) cov = cov[:, :, newaxis] return y, z, [lamb, prec, cov]
def _inv(self, src): dst = inv(src.transpose(2, 0, 1)).transpose(1, 2, 0) return dst