def normalize_observation(observation): observation = _unit_norm( observation, axis=-1, eps=np.finfo(observation.dtype).tiny, eps_style='where', ) return np.ascontiguousarray(np.swapaxes(observation, -2, -1))
def _m_step( self, x, quadratic_form, affiliation, saliency, dirichlet_prior_concentration, hermitize, covariance_norm, eigenvalue_floor, weight_constant_axis, ): if saliency is None: masked_affiliation = affiliation if dirichlet_prior_concentration == 1: weight = np.mean(affiliation, axis=weight_constant_axis, keepdims=True) elif np.isposinf(dirichlet_prior_concentration): *independent, K, T = affiliation.shape[-2:] weight = np.broadcast_to(1 / K, [*independent, K, 1]) else: assert dirichlet_prior_concentration >= 1, dirichlet_prior_concentration assert weight_constant_axis == (-1, ), ( 'ToDo: implement weight_constant_axis ({}) for ' 'dirichlet_prior_concentration ({}).').format( weight_constant_axis, dirichlet_prior_concentration) # affiliation: ..., K, T tmp = np.sum(affiliation, axis=weight_constant_axis, keepdims=True) K, T = affiliation.shape[-2:] weight = (tmp + (dirichlet_prior_concentration - 1)) / ( T + (dirichlet_prior_concentration - 1) * K) else: assert dirichlet_prior_concentration == 1, dirichlet_prior_concentration masked_affiliation = affiliation * saliency[..., None, :] weight = _unit_norm( np.sum(masked_affiliation, axis=weight_constant_axis, keepdims=True), ord=1, axis=-1, eps=1e-10, eps_style='where', ) cacg = ComplexAngularCentralGaussianTrainer()._fit( y=x[..., None, :, :], saliency=masked_affiliation, quadratic_form=quadratic_form, hermitize=hermitize, covariance_norm=covariance_norm, eigenvalue_floor=eigenvalue_floor, ) return CACGMM(weight=weight, cacg=cacg)
def _estimate_mixture_weight_with_dirichlet_prior_concentration( affiliation, saliency=None, weight_constant_axis=-1, dirichlet_prior_concentration=1, ): """ This function is a starting point for those that want to use a Dirichlet prior with a plug-in rule (i.e. MAP estimate instead of MMSE estimate). """ affiliation = np.asarray(affiliation) if isinstance(weight_constant_axis, int) and \ weight_constant_axis % affiliation.ndim - affiliation.ndim == -2: K = affiliation.shape[-2] return np.full([K, 1], 1 / K) if saliency is None: if dirichlet_prior_concentration == 1: weight = np.mean(affiliation, axis=weight_constant_axis, keepdims=True) elif np.isposinf(dirichlet_prior_concentration): *independent, K, T = affiliation.shape[-2:] weight = np.broadcast_to(1 / K, [*independent, K, 1]) else: assert dirichlet_prior_concentration >= 1, dirichlet_prior_concentration # noqa assert weight_constant_axis == (-1, ), ( 'ToDo: implement weight_constant_axis ({}) for ' 'dirichlet_prior_concentration ({}).').format( weight_constant_axis, dirichlet_prior_concentration) # affiliation: ..., K, T tmp = np.sum(affiliation, axis=weight_constant_axis, keepdims=True) K, T = affiliation.shape[-2:] weight = (tmp + (dirichlet_prior_concentration - 1)) / ( T + (dirichlet_prior_concentration - 1) * K) else: assert dirichlet_prior_concentration == 1, dirichlet_prior_concentration # noqa masked_affiliation = affiliation * saliency[..., None, :] weight = _unit_norm( np.sum(masked_affiliation, axis=weight_constant_axis, keepdims=True), ord=1, axis=-1, eps=1e-10, eps_style='where', ) return weight
def _m_step( self, x, quadratic_form, affiliation, saliency, dirichlet_prior_concentration, hermitize, covariance_norm, eigenvalue_floor, ): if saliency is None: masked_affiliation = affiliation if dirichlet_prior_concentration == 1: weight = np.mean(affiliation, axis=-1) elif np.isposinf(dirichlet_prior_concentration): K, T = affiliation.shape[-2:] weight = np.broadcast_to(1 / K, affiliation.shape[:-1]) else: assert dirichlet_prior_concentration >= 1, dirichlet_prior_concentration # affiliation: ..., K, T tmp = np.sum(affiliation, axis=-1) K, T = affiliation.shape[-2:] weight = (tmp + (dirichlet_prior_concentration - 1)) / ( T + (dirichlet_prior_concentration - 1) * K) else: assert dirichlet_prior_concentration == 1, dirichlet_prior_concentration masked_affiliation = affiliation * saliency[..., None, :] weight = _unit_norm( np.sum(masked_affiliation, axis=-1), ord=1, axis=-1, eps=1e-10, eps_style='where', ) cacg = ComplexAngularCentralGaussianTrainer()._fit( y=x[..., None, :, :], saliency=masked_affiliation, quadratic_form=quadratic_form, hermitize=hermitize, covariance_norm=covariance_norm, eigenvalue_floor=eigenvalue_floor, ) return CACGMM(weight=weight, cacg=cacg)
def normalize_observation(observation): """ Attention: swap D and N dim The dimensions are swapped, because some calculations (e.g. covariance) do a reduction over the sample (time) dimension. Having the time dimension on the last axis improves the execution time. Args: observation: (..., N, D) Returns: normalized observation (..., D, N) """ observation = _unit_norm( observation, axis=-1, eps=np.finfo(observation.dtype).tiny, eps_style='where', ) return np.ascontiguousarray(np.swapaxes(observation, -2, -1))
def estimate_mixture_weight( affiliation, saliency=None, weight_constant_axis=-1, ): """ Estimates the mixture weight of a mixture model. The simplest version (without saliency and prior): return np.mean(affiliation, axis=weight_constant_axis, keepdims=True) Args: affiliation: Shape: (..., K, T) saliency: Shape: (..., K, T) weight_constant_axis: int Returns: mixture weight with the same shape as affiliation, except for the weight_constant_axis that is a singleton: e.g. for weight_constant_axis == -1: (..., K, 1) When the weight_constant_axis is -2 or the positive counterpart, then the returned shape is always (K, 1) and the value if 1/K. >>> affiliation = [[0.4, 1, 0.4], [0.6, 0, 0.6]] >>> estimate_mixture_weight(affiliation) array([[0.6], [0.4]]) >>> estimate_mixture_weight(affiliation, weight_constant_axis=-2) array([[0.5], [0.5]]) >>> estimate_mixture_weight([affiliation, affiliation]) array([[[0.6], [0.4]], <BLANKLINE> [[0.6], [0.4]]]) >>> estimate_mixture_weight([affiliation, affiliation], weight_constant_axis=-2) array([[0.5], [0.5]]) >>> estimate_mixture_weight([affiliation, affiliation], weight_constant_axis=-3) array([[[0.4, 1. , 0.4], [0.6, 0. , 0.6]]]) """ affiliation = np.asarray(affiliation) if isinstance(weight_constant_axis, int) and \ weight_constant_axis % affiliation.ndim - affiliation.ndim == -2: K = affiliation.shape[-2] return np.full([K, 1], 1 / K) elif isinstance(weight_constant_axis, list): weight_constant_axis = tuple(weight_constant_axis) if saliency is None: weight = np.mean(affiliation, axis=weight_constant_axis, keepdims=True) else: masked_affiliation = affiliation * saliency[..., None, :] weight = _unit_norm( np.sum(masked_affiliation, axis=weight_constant_axis, keepdims=True), ord=1, axis=-2, eps=1e-10, eps_style='where', ) return weight