def __post_init__(self): D = self.mean.shape[-1] c = np.reshape(self.covariance, (-1, )) pc = _compute_precision_cholesky(c, 'diag') self.precision_cholesky = np.reshape(pc, self.covariance.shape) self.log_det_precision_cholesky = _compute_log_det_cholesky( pc, 'spherical', D)
def __post_init__(self): D = self.mean.shape[-1] c = np.reshape(self.covariance, (-1, D, D)) pc = _compute_precision_cholesky(c, 'full') self.precision_cholesky = np.reshape(pc, self.covariance.shape) self.log_det_precision_cholesky = np.reshape( _compute_log_det_cholesky(pc, 'full', D), self.covariance.shape[:-2])
def _estimate_log_gaussian_prob(X, means, precisions_chol, covariance_type): """Estimate the log Gaussian probability. Parameters ---------- X : array-like, shape (n_samples, n_features) means : array-like, shape (n_components, n_features) precisions_chol : array-like Cholesky decompositions of the precision matrices. 'full' : shape of (n_components, n_features, n_features) 'tied' : shape of (n_features, n_features) 'diag' : shape of (n_components, n_features) 'spherical' : shape of (n_components,) covariance_type : {'full', 'tied', 'diag', 'spherical'} Returns ------- log_prob : array, shape (n_samples, n_components) """ n_samples, n_features = X.shape n_components, _ = means.shape # det(precision_chol) is half of det(precision) log_det = _compute_log_det_cholesky(precisions_chol, covariance_type, n_features) if covariance_type == 'full': log_prob = np.empty((n_samples, n_components)) for k, (mu, prec_chol) in enumerate(zip(means, precisions_chol)): y = np.dot(X, prec_chol) - np.dot(mu, prec_chol) #print(y.shape) #print(np.argmax(np.square(y), axis=1)) square_y = np.square(y) weighted_square_y = square_y #print(y.shape[1]-1) #print(square_y[0:2,:]) weighted_square_y[:, -1] *= y.shape[1] - 1 #print(weighted_square_y[0:2, :]) log_prob[:, k] = np.sum(weighted_square_y, axis=1) return -.5 * (n_features * np.log(2 * np.pi) + log_prob) + log_det
def test_compute_log_det_cholesky(): n_features = 2 rand_data = RandomData(np.random.RandomState(0)) for covar_type in COVARIANCE_TYPE: covariance = rand_data.covariances[covar_type] if covar_type == 'full': predected_det = np.array([linalg.det(cov) for cov in covariance]) elif covar_type == 'tied': predected_det = linalg.det(covariance) elif covar_type == 'diag': predected_det = np.array([np.prod(cov) for cov in covariance]) elif covar_type == 'spherical': predected_det = covariance ** n_features # We compute the cholesky decomposition of the covariance matrix expected_det = _compute_log_det_cholesky(_compute_precision_cholesky( covariance, covar_type), covar_type, n_features=n_features) assert_array_almost_equal(expected_det, - .5 * np.log(predected_det))
def test_compute_log_det_cholesky(): n_features = 2 rand_data = RandomData(np.random.RandomState(0)) for covar_type in COVARIANCE_TYPE: covariance = rand_data.covariances[covar_type] if covar_type == 'full': predected_det = np.array([linalg.det(cov) for cov in covariance]) elif covar_type == 'tied': predected_det = linalg.det(covariance) elif covar_type == 'diag': predected_det = np.array([np.prod(cov) for cov in covariance]) elif covar_type == 'spherical': predected_det = covariance ** n_features # We compute the cholesky decomposition of the covariance matrix expected_det = _compute_log_det_cholesky(_compute_precision_cholesky( covariance, covar_type), covar_type, n_features=n_features) assert_array_almost_equal(expected_det, - .5 * np.log(predected_det))
def convert_sklearn_gaussian_mixture(scope, operator, container): """ Converter for *GaussianMixture*, *BayesianGaussianMixture*. Parameters which change the prediction function: * *covariance_type* """ X = operator.inputs[0] out = operator.outputs op = operator.raw_operator n_features = X.type.shape[1] n_components = op.means_.shape[0] # All comments come from scikit-learn code and tells # which functions is being onnxified. # def _estimate_weighted_log_prob(self, X): # self._estimate_log_prob(X) + self._estimate_log_weights() log_weights = np.log(op.weights_) # self._estimate_log_weights() # self._estimate_log_prob(X) log_det = _compute_log_det_cholesky(op.precisions_cholesky_, op.covariance_type, n_features) if op.covariance_type == 'full': # shape(op.means_) = (n_components, n_features) # shape(op.precisions_cholesky_) = # (n_components, n_features, n_features) # log_prob = np.empty((n_samples, n_components)) # for k, (mu, prec_chol) in enumerate(zip(means, precisions_chol)): # y = np.dot(X, prec_chol) - np.dot(mu, prec_chol) # log_prob[:, k] = np.sum(np.square(y), axis=1) ys = [] for c in range(n_components): prec_chol = op.precisions_cholesky_[c, :, :] cst = -np.dot(op.means_[c, :], prec_chol) y = OnnxGemm(X, prec_chol, cst, alpha=1., beta=1.) y2s = OnnxReduceSumSquare(y, axes=[1]) ys.append(y2s) log_prob = OnnxConcat(*ys, axis=1) elif op.covariance_type == 'tied': # shape(op.means_) = (n_components, n_features) # shape(op.precisions_cholesky_) = # (n_features, n_features) # log_prob = np.empty((n_samples, n_components)) # for k, mu in enumerate(means): # y = np.dot(X, precisions_chol) - np.dot(mu, precisions_chol) # log_prob[:, k] = np.sum(np.square(y), axis=1) precisions_chol = op.precisions_cholesky_ ys = [] for f in range(n_components): cst = -np.dot(op.means_[f, :], precisions_chol) y = OnnxGemm(X, precisions_chol, cst, alpha=1., beta=1.) y2s = OnnxReduceSumSquare(y, axes=[1]) ys.append(y2s) log_prob = OnnxConcat(*ys, axis=1) elif op.covariance_type == 'diag': # shape(op.means_) = (n_components, n_features) # shape(op.precisions_cholesky_) = # (n_components, n_features) # precisions = precisions_chol ** 2 # log_prob = (np.sum((means ** 2 * precisions), 1) - # 2. * np.dot(X, (means * precisions).T) + # np.dot(X ** 2, precisions.T)) precisions = op.precisions_cholesky_**2 mp = np.sum((op.means_**2 * precisions), 1) zeros = np.zeros((n_components, )) xmp = OnnxGemm(X, (op.means_ * precisions).T, zeros, alpha=-2., beta=0.) term = OnnxGemm(OnnxMul(X, X), precisions.T, zeros, alpha=1., beta=0.) log_prob = OnnxAdd(OnnxAdd(mp, xmp), term) elif op.covariance_type == 'spherical': # shape(op.means_) = (n_components, n_features) # shape(op.precisions_cholesky_) = (n_components, ) # precisions = precisions_chol ** 2 # log_prob = (np.sum(means ** 2, 1) * precisions - # 2 * np.dot(X, means.T * precisions) + # np.outer(row_norms(X, squared=True), precisions)) zeros = np.zeros((n_components, )) precisions = op.precisions_cholesky_**2 normX = OnnxReduceSumSquare(X, axes=[1]) outer = OnnxGemm(normX, precisions[np.newaxis, :], zeros, alpha=1., beta=1.) xmp = OnnxGemm(X, (op.means_.T * precisions), zeros, alpha=-2., beta=0.) mp = np.sum(op.means_**2, 1) * precisions log_prob = OnnxAdd(mp, OnnxAdd(xmp, outer)) else: raise RuntimeError("Unknown op.covariance_type='{}'. Upgrade " "to a mroe recent version of skearn-onnx " "or raise an issue.".format(op.covariance_type)) # -.5 * (cst + log_prob) + log_det cst = np.array([n_features * np.log(2 * np.pi)]) add = OnnxAdd(cst, log_prob) mul = OnnxMul(add, np.array([-0.5])) if isinstance(log_det, float): log_det = np.array([log_det]) weighted_log_prob = OnnxAdd(OnnxAdd(mul, log_det), log_weights) # labels labels = OnnxArgMax(weighted_log_prob, axis=1, output_names=out[:1]) # def _estimate_log_prob_resp(): # np.exp(log_resp) # weighted_log_prob = self._estimate_weighted_log_prob(X) # log_prob_norm = logsumexp(weighted_log_prob, axis=1) # with np.errstate(under='ignore'): # log_resp = weighted_log_prob - log_prob_norm[:, np.newaxis] log_prob_norm = OnnxReduceLogSumExp(weighted_log_prob, axes=[1]) log_resp = OnnxSub(weighted_log_prob, log_prob_norm) # probabilities probs = OnnxExp(log_resp, output_names=out[1:]) # final labels.add_to(scope, container) probs.add_to(scope, container)