def jsd_diss(self, w1, mu1, cov1, w2, mu2, cov2): """ Calculates Jensen-Shannon divergence of two gmm's :param gmm_p: mixture.GaussianMixture :param gmm_q: mixture.GaussianMixture :param sample_count: number of monte carlo samples to use :return: Jensen-Shannon divergence """ gmm_p = GaussianMixture(n_components=n_components, covariance_type="full") gmm_p.weights_ = w1 gmm_p.covariances_ = cov1 gmm_p.means_ = mu1 gmm_p.n_components = 1 gmm_p.precisions_cholesky_ = _compute_precision_cholesky(cov1, "full") gmm_q = GaussianMixture(n_components=n_components, covariance_type="full") gmm_q.weights_ = w2 gmm_q.covariances_ = cov2 gmm_q.means_ = mu2 gmm_q.n_components = 1 gmm_q.precisions_cholesky_ = _compute_precision_cholesky(cov2, "full") X = gmm_p.sample(sample_count)[0] log_p_X = gmm_p.score_samples(X) log_q_X = gmm_q.score_samples(X) log_mix_X = np.logaddexp(log_p_X, log_q_X) Y = gmm_q.sample(sample_count)[0] log_p_Y = gmm_p.score_samples(Y) log_q_Y = gmm_q.score_samples(Y) log_mix_Y = np.logaddexp(log_p_Y, log_q_Y) # black magic? return (log_p_X.mean() - (log_mix_X.mean() - np.log(2)) + log_q_Y.mean() - (log_mix_Y.mean() - np.log(2))) / 2
def gmm_combine(gmms, weights=None, params=None, good_idx=None, gmms_means=None, gmms_variances=None, gmms_weights=None, gmms_zps=None): """ Method to combine Gaussian Mixture Models. This function create a new GaussianMixture instance and adds all mixture components from the input models. Parameters ---------- gmms List of GaussianMixture instances to combine. weights : iterable, optional Weights for each GaussianMixture instance in the input list. params : dict, optional GaussianMixture parameter dictionary for faster instantiation. good_idx : iterable, optional Boolean array or list for masking. True indicates a good entry in the input list, False a bad entry. gmms_means : np.ndarray, optional The means of all components for all input GMMs in an array. Can be used to speed up the combination process- gmms_variances : np.ndarray, optional Same as gmms_means, but for all variances of all components. gmms_weights : np.ndarray, optional Same as gmms_means, but for all weights of all components. gmms_zps : np.ndarray, optional Zero point for all models. If None is given, no shift is applied. Returns ------- GaussianMixture Combined GaussianMixture instance. """ # Dummy checks if not isinstance(gmms, Iterable): raise ValueError("Models must be provided as an iterable") # Set good_idx if good_idx is None: good_idx = [True for _ in range(len(gmms))] # Extract good GMMs gmms = gmms[good_idx] # Set weights to unity if not specified if weights is None: weights = [1 for _ in range(len(gmms))] else: weights = weights[good_idx] # Return None if weights are all bad if np.sum(np.isfinite(weights)) == 0: return None # Set zeropoints if not specified if gmms_zps is None: gmms_zps = [0. for _ in range(len(gmms))] else: gmms_zps = gmms_zps[good_idx] # Get parameters if not set from first entry if params is None: params = gmms[0].get_params() # Dummy check if np.sum([isinstance(g, GaussianMixture) for g in gmms]) != len(gmms): raise ValueError("Must only supply GaussianMixture instances") # Instantiate combined GMM gmm_combined = GaussianMixture(**params) # Build combined components from supplied models if not given as attributes if gmms_means is None or gmms_variances is None or gmms_weights is None: gmm_combined_means = gmms[0].means_ + gmms_zps[0] gmm_combined_variances = gmms[0].covariances_ gmm_combined_weights = gmms[0].weights_ * weights[0] for gmm, w, zp in zip(gmms[1:], weights[1:], gmms_zps[1:]): gmm_combined_means = np.vstack([gmm_combined_means, gmm.means_ + zp]) gmm_combined_variances = np.vstack([gmm_combined_variances, gmm.covariances_]) gmm_combined_weights = np.hstack([gmm_combined_weights, gmm.weights_ * w]) # If the attributes are provided, extract the parameters directly (much faster) else: gmm_combined_means = np.vstack(gmms_means[good_idx] + gmms_zps) gmm_combined_variances = np.vstack(gmms_variances[good_idx]) gmm_combined_weights = np.hstack(gmms_weights[good_idx] * weights) # Add attributes to new mixture gmm_combined.n_components = len(gmm_combined_means) gmm_combined.means_ = gmm_combined_means gmm_combined.covariances_ = gmm_combined_variances gmm_combined.weights_ = gmm_combined_weights / np.sum(gmm_combined_weights) gmm_combined.precisions_ = np.linalg.inv(gmm_combined.covariances_) gmm_combined.precisions_cholesky_ = np.linalg.cholesky(gmm_combined.precisions_) # Add attribute to store number of input models used to create this model gmm_combined.n_models = len(gmms) # Return new GMM return gmm_combined