def _m_step_nu(self, expectations, datas, inputs, masks, tags, optimizer, num_iters, **kwargs): K, D = self.K, self.D E_taus = np.zeros(K) E_logtaus = np.zeros(K) weights = np.zeros(K) for ( Ez, _, _, ), data, input, mask, tag in zip(expectations, datas, inputs, masks, tags): # nu: (K,) mus: (K, D) sigmas: (K, D) y: (T, D) -> w: (T, K, D) mus = self._compute_mus(data, input, mask, tag) sigmas = self._compute_sigmas(data, input, mask, tag) nus = np.exp(self.inv_nus[:, None]) alpha = nus / 2 + 1 / 2 beta = nus / 2 + 1 / 2 * (data[:, None, :] - mus)**2 / sigmas E_taus += np.sum(Ez[:, :, None] * alpha / beta, axis=(0, 2)) E_logtaus += np.sum(Ez[:, :, None] * (digamma(alpha) - np.log(beta)), axis=(0, 2)) weights += np.sum(Ez, axis=0) * D E_taus /= weights E_logtaus /= weights for k in range(K): self.inv_nus[k] = np.log( generalized_newton_studentst_dof(E_taus[k], E_logtaus[k]))
def _m_step_nu(self, expectations, datas, inputs, masks, tags): """ The shape parameter nu determines a gamma prior. We have tau_n ~ Gamma(nu/2, nu/2) y_n ~ N(mu, sigma^2 / tau_n) To update nu, we do EM and optimize the expected log likelihood using a generalized Newton's method. See the notebook in doc/students_t for complete details. """ K, D = self.K, self.D # Compute the precisions w for each data point E_taus = np.zeros(K) E_logtaus = np.zeros(K) weights = np.zeros(K) for y, (Ez, _, _) in zip(datas, expectations): # nu: (K,) mus: (K, D) sigmas: (K, D) y: (T, D) -> alpha/beta: (T, K, D) nus = np.exp(self.inv_nus[:, None]) alpha = nus/2 + 1/2 beta = nus/2 + 1/2 * (y[:, None, :] - self.mus)**2 / np.exp(self.inv_sigmas) E_taus += np.sum(Ez[:, :, None] * alpha / beta, axis=(0, 2)) E_logtaus += np.sum(Ez[:, :, None] * (digamma(alpha) - np.log(beta)), axis=(0, 2)) weights += np.sum(Ez, axis=0) * D E_taus /= weights E_logtaus /= weights for k in range(K): self.inv_nus[k] = np.log(generalized_newton_studentst_dof(E_taus[k], E_logtaus[k]))