diff --git a/HISTORY.md b/HISTORY.md index 9bb3ab077c..74a68f4f68 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -24,11 +24,14 @@ * CMake fix for finding STB include directory (#2145). * Add normalization support for CF binding (#2136). - + * Add Mish activation function (#2158). * Add GELU activation function (#2183). + * Better error handling of eigendecompositions and Cholesky decompositions + (#2088, #1840). + ### mlpack 3.2.2 ###### 2019-11-26 * Add `valid` and `same` padding option in `Convolution` and `Atrous diff --git a/src/mlpack/core/boost_backport/collections_load_imp.hpp b/src/mlpack/core/boost_backport/collections_load_imp.hpp old mode 100755 new mode 100644 diff --git a/src/mlpack/core/boost_backport/collections_save_imp.hpp b/src/mlpack/core/boost_backport/collections_save_imp.hpp old mode 100755 new mode 100644 diff --git a/src/mlpack/core/boost_backport/vector.hpp b/src/mlpack/core/boost_backport/vector.hpp old mode 100755 new mode 100644 diff --git a/src/mlpack/core/dists/gaussian_distribution.cpp b/src/mlpack/core/dists/gaussian_distribution.cpp index b112a7c3c9..812b9d6dd7 100644 --- a/src/mlpack/core/dists/gaussian_distribution.cpp +++ b/src/mlpack/core/dists/gaussian_distribution.cpp @@ -39,8 +39,11 @@ void GaussianDistribution::Covariance(arma::mat&& covariance) void GaussianDistribution::FactorCovariance() { // On Armadillo < 4.500, the "lower" option isn't available. - covLower = arma::chol(covariance, "lower"); + if (!arma::chol(covLower, covariance, "lower")) + { + Log::Fatal << "Cholesky decomposition failed." << std::endl; + } // Comment from rcurtin: // // I think the use of the word "interpret" in the Armadillo documentation diff --git a/src/mlpack/core/math/lin_alg.cpp b/src/mlpack/core/math/lin_alg.cpp index 822625a59b..48919ce56f 100644 --- a/src/mlpack/core/math/lin_alg.cpp +++ b/src/mlpack/core/math/lin_alg.cpp @@ -73,32 +73,6 @@ void mlpack::math::WhitenUsingSVD(const arma::mat& x, xWhitened = whiteningMatrix * x; } -/** - * Whitens a matrix using the eigendecomposition of the covariance matrix. - * Whitening means the covariance matrix of the result is the identity matrix. - */ -void mlpack::math::WhitenUsingEig(const arma::mat& x, - arma::mat& xWhitened, - arma::mat& whiteningMatrix) -{ - arma::mat diag, eigenvectors; - arma::vec eigenvalues; - - // Get eigenvectors of covariance of input matrix. - eig_sym(eigenvalues, eigenvectors, mlpack::math::ColumnCovariance(x)); - - // Generate diagonal matrix using 1 / sqrt(eigenvalues) for each value. - VectorPower(eigenvalues, -0.5); - diag.zeros(eigenvalues.n_elem, eigenvalues.n_elem); - diag.diag() = eigenvalues; - - // Our whitening matrix is diag(1 / sqrt(eigenvectors)) * eigenvalues. - whiteningMatrix = diag * trans(eigenvectors); - - // Now apply the whitening matrix. - xWhitened = whiteningMatrix * x; -} - /** * Overwrites a dimension-N vector to a random vector on the unit sphere in R^N. */ diff --git a/src/mlpack/core/math/lin_alg.hpp b/src/mlpack/core/math/lin_alg.hpp index 07b9bf720d..c498920752 100644 --- a/src/mlpack/core/math/lin_alg.hpp +++ b/src/mlpack/core/math/lin_alg.hpp @@ -45,13 +45,6 @@ void WhitenUsingSVD(const arma::mat& x, arma::mat& xWhitened, arma::mat& whiteningMatrix); -/** - * Whitens a matrix using the eigendecomposition of the covariance matrix. - * Whitening means the covariance matrix of the result is the identity matrix. - */ -void WhitenUsingEig(const arma::mat& x, - arma::mat& xWhitened, - arma::mat& whiteningMatrix); /** * Overwrites a dimension-N vector to a random vector on the unit sphere in R^N. diff --git a/src/mlpack/methods/ann/layer/transposed_convolution.hpp b/src/mlpack/methods/ann/layer/transposed_convolution.hpp old mode 100755 new mode 100644 diff --git a/src/mlpack/methods/ann/layer/transposed_convolution_impl.hpp b/src/mlpack/methods/ann/layer/transposed_convolution_impl.hpp old mode 100755 new mode 100644 diff --git a/src/mlpack/methods/gmm/eigenvalue_ratio_constraint.hpp b/src/mlpack/methods/gmm/eigenvalue_ratio_constraint.hpp index c33888a7d5..0aa9760e74 100644 --- a/src/mlpack/methods/gmm/eigenvalue_ratio_constraint.hpp +++ b/src/mlpack/methods/gmm/eigenvalue_ratio_constraint.hpp @@ -64,7 +64,12 @@ class EigenvalueRatioConstraint // Eigendecompose the matrix. arma::vec eigenvalues; arma::mat eigenvectors; - arma::eig_sym(eigenvalues, eigenvectors, covariance); + covariance = arma::symmatu(covariance); + if (!arma::eig_sym(eigenvalues, eigenvectors, covariance)) + { + Log::Fatal << "applying to constraint could not be accomplished." + << std::endl; + } // Change the eigenvalues to what we are forcing them to be. There // shouldn't be any negative eigenvalues anyway, so it doesn't matter if we diff --git a/src/mlpack/methods/gmm/gmm.cpp b/src/mlpack/methods/gmm/gmm.cpp index 91847f0690..6286b15143 100644 --- a/src/mlpack/methods/gmm/gmm.cpp +++ b/src/mlpack/methods/gmm/gmm.cpp @@ -117,7 +117,12 @@ arma::vec GMM::Random() const } } - return trans(chol(dists[gaussian].Covariance())) * + arma::mat cholDecomp; + if (!arma::chol(cholDecomp, dists[gaussian].Covariance())) + { + Log::Fatal << "Cholesky decomposition failed." << std::endl; + } + return trans(cholDecomp) * arma::randn(dimensionality) + dists[gaussian].Mean(); } diff --git a/src/mlpack/methods/gmm/positive_definite_constraint.hpp b/src/mlpack/methods/gmm/positive_definite_constraint.hpp index c41d38de46..2e5d33892d 100644 --- a/src/mlpack/methods/gmm/positive_definite_constraint.hpp +++ b/src/mlpack/methods/gmm/positive_definite_constraint.hpp @@ -41,7 +41,12 @@ class PositiveDefiniteConstraint // eigenvalues are at least 1e-50). arma::vec eigval; arma::mat eigvec; - arma::eig_sym(eigval, eigvec, covariance); + covariance = arma::symmatu(covariance); + if (!arma::eig_sym(eigval, eigvec, covariance)) + { + Log::Fatal << "applying to constraint could not be accomplished." + << std::endl; + } // If the matrix is not positive definite or if the condition number is // large, we must project it back onto the cone of positive definite diff --git a/src/mlpack/methods/kernel_pca/kernel_rules/naive_method.hpp b/src/mlpack/methods/kernel_pca/kernel_rules/naive_method.hpp index 567ab51b83..193a64a30c 100644 --- a/src/mlpack/methods/kernel_pca/kernel_rules/naive_method.hpp +++ b/src/mlpack/methods/kernel_pca/kernel_rules/naive_method.hpp @@ -73,7 +73,11 @@ class NaiveKernelRule kernelMatrix += arma::sum(rowMean) / kernelMatrix.n_cols; // Eigendecompose the centered kernel matrix. - arma::eig_sym(eigval, eigvec, kernelMatrix); + kernelMatrix = arma::symmatu(kernelMatrix); + if (!arma::eig_sym(eigval, eigvec, kernelMatrix)) + { + Log::Fatal << "Failed to construct the kernel matrix." << std::endl; + } // Swap the eigenvalues since they are ordered backwards (we need largest to // smallest). diff --git a/src/mlpack/methods/kernel_pca/kernel_rules/nystroem_method.hpp b/src/mlpack/methods/kernel_pca/kernel_rules/nystroem_method.hpp index 3ee0b0aed7..cdbc0a55fc 100644 --- a/src/mlpack/methods/kernel_pca/kernel_rules/nystroem_method.hpp +++ b/src/mlpack/methods/kernel_pca/kernel_rules/nystroem_method.hpp @@ -64,7 +64,11 @@ class NystroemKernelRule G += arma::sum(colMean) / G.n_rows; // Eigendecompose the centered kernel matrix. - arma::eig_sym(eigval, eigvec, transformedData); + transformedData = arma::symmatu(transformedData); + if (!arma::eig_sym(eigval, eigvec, transformedData)) + { + Log::Fatal << "Failed to construct the kernel matrix." << std::endl; + } // Swap the eigenvalues since they are ordered backwards (we need largest // to smallest). diff --git a/src/mlpack/methods/reinforcement_learning/environment/double_pole_cart.hpp b/src/mlpack/methods/reinforcement_learning/environment/double_pole_cart.hpp old mode 100755 new mode 100644 diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp old mode 100755 new mode 100644 diff --git a/src/mlpack/tests/data/test_data_3_1000.csv b/src/mlpack/tests/data/test_data_3_1000.csv old mode 100755 new mode 100644 diff --git a/src/mlpack/tests/lin_alg_test.cpp b/src/mlpack/tests/lin_alg_test.cpp index cd1f3ced85..ecccae50e7 100644 --- a/src/mlpack/tests/lin_alg_test.cpp +++ b/src/mlpack/tests/lin_alg_test.cpp @@ -78,37 +78,6 @@ BOOST_AUTO_TEST_CASE(TestCenterB) BOOST_REQUIRE_CLOSE(tmp_out(row, col), (double) (col - 2.5) * row, 1e-5); } -BOOST_AUTO_TEST_CASE(TestWhitenUsingEig) -{ - // After whitening using eigendecomposition, the covariance of - // our matrix will be I (or something very close to that). - // We are loading a matrix from an external file... bad choice. - mat tmp, tmp_centered, whitened, whitening_matrix; - - data::Load("trainSet.csv", tmp); - Center(tmp, tmp_centered); - WhitenUsingEig(tmp_centered, whitened, whitening_matrix); - - mat newcov = mlpack::math::ColumnCovariance(whitened); - for (int row = 0; row < 5; row++) - { - for (int col = 0; col < 5; col++) - { - if (row == col) - { - // diagonal will be 0 in the case of any zero-valued eigenvalues - // (rank-deficient covariance case) - if (std::abs(newcov(row, col)) > 1e-10) - BOOST_REQUIRE_CLOSE(newcov(row, col), 1.0, 1e-10); - } - else - { - BOOST_REQUIRE_SMALL(newcov(row, col), 1e-10); - } - } - } -} - BOOST_AUTO_TEST_CASE(TestOrthogonalize) { // Generate a random matrix; then, orthogonalize it and test if it's