def preprocessData(self, ys, u=None, computeMarginal=True): ys is not None ys = np.array(ys) if (ys.ndim == 2): ys = ys[None] else: assert ys.ndim == 3 assert self.J1Emiss.shape[0] == ys.shape[2] self._T = ys.shape[1] # This is A.T @ sigInv @ y for each y, summed over each measurement self.hy = ys.dot(self._hy).sum(axis=0) # P( y | x ) ~ N( -0.5 * Jy, hy ) self.computeMarginal = computeMarginal if (computeMarginal): print('self.Jy', self.Jy) print('self.hy', self.hy) partition = np.vectorize( lambda J, h: Normal.log_partition(nat_params=(-0.5 * J, h)), signature='(n,n),(n)->()') self.log_Zy = partition(self.Jy, self.hy) else: self.log_Zy = np.zeros(self.hy.shape[0]) if (u is not None): assert u.shape == (self.T, self.D_latent) uMask = np.isnan(u) self.u = (u, uMask, None)
def log_partition( cls, x=None, params=None, nat_params=None, split=False ): # Compute A( Ѳ ) - log( h( x ) ) assert ( params is None ) ^ ( nat_params is None ) # Need to multiply each partition by the length of each sequence!!!! A, sigma, C, R, mu0, sigma0 = params if params is not None else cls.natToStandard( *nat_params ) A1, A2 = Regression.log_partition( params=( A, sigma ), split=True ) A3, A4 = Regression.log_partition( params=( C, R ), split=True ) A5, A6, A7 = Normal.log_partition( params=( mu0, sigma0 ), split=True ) if( split == True ): return A1, A2, A3, A4, A5, A6, A7 return A1 + A2 + A3 + A4 + A5 + A6 + A7
def updateNatParams(self, z, n1Trans, n2Trans, n3Trans, n1Emiss, n2Emiss, n3Emiss, n1Init, n2Init, u=None, ys=None, computeMarginal=True): self._D_latent = n2Init.shape[0] self._D_obs = n1Emiss.shape[0] self.z = z self.J11s = [-2 * n for n in n1Trans] self.J12s = [-n.T for n in n3Trans] self.J22s = [-2 * n for n in n2Trans] self.log_Zs = [ 0.5 * np.linalg.slogdet(np.linalg.inv(J11))[1] for J11 in self.J11s ] if computeMarginal else [0 for _ in self.J11s] self.J1Emiss = -2 * n1Emiss self.Jy = -2 * n2Emiss self._hy = n3Emiss.T self.J0 = -2 * n1Init self.h0 = n2Init self.log_Z0 = Normal.log_partition( nat_params=(-2 * self.J0, self.h0)) if computeMarginal else 0 if (ys is not None): self.preprocessData(ys, computeMarginal=computeMarginal) else: self._T = None if (u is not None): assert u.shape == (self.T, self.D_latent) uMask = np.isnan(u) self.u = (u, uMask, None) else: uMask = np.zeros(self.T, dtype=bool) self.u = (None, uMask, self.D_latent)
def updateNatParams(self, n1Trans, n2Trans, n3Trans, n1Emiss, n2Emiss, n3Emiss, n1Init, n2Init, u=None, ys=None, computeMarginal=True): # This doesn't exactly use natural parameters, but uses J = -2 * n1 and h = n2 self._D_latent = n1Trans.shape[0] self._D_obs = n1Emiss.shape[0] self.J11 = -2 * n1Trans self.J12 = -n3Trans.T self.J22 = -2 * n2Trans self.log_Z = 0.5 * np.linalg.slogdet(np.linalg.inv( self.J11))[1] if computeMarginal else 0 self.J1Emiss = -2 * n1Emiss self.Jy = -2 * n2Emiss self._hy = n3Emiss.T self.J0 = -2 * n1Init self.h0 = n2Init self.log_Z0 = Normal.log_partition( nat_params=(-2 * self.J0, self.h0)) if computeMarginal else 0 if (ys is not None): self.preprocessData(ys, computeMarginal=computeMarginal) else: self._T = None if (u is not None): assert u.shape == (self.T, self.D_latent) uMask = np.isnan(u) self.u = (u, uMask, None) else: uMask = np.zeros(self.T, dtype=bool) self.u = (None, uMask, self.D_latent) self.fromNatural = True
def emissionProb(self, t, forward=False, ys=None): # P( y_t | x_t ) as a function of x_t J = self.Jy if (ys is None): h = self.hy[t] log_Z = self.log_Zy[t] else: # A.T @ sigInv @ y h = np.einsum('ji,mj->i', self._hy, ys[:, t]) log_Z = Normal.log_partition(nat_params=(-0.5 * self.Jy, h)) if (forward): return J, h, np.array(log_Z) # Because this is before the integration step return self.alignOnUpper(J, h, log_Z)
def log_marginalFromAlphaBeta(cls, alpha, beta): Ja, ha, log_Za = alpha Jb, hb, log_Zb = beta return Normal.log_partition(nat_params=(-0.5 * (Ja + Jb), (ha + hb))) - (log_Za + log_Zb)