diff --git a/paddle/fluid/operators/cholesky_op.cu b/paddle/fluid/operators/cholesky_op.cu index c44299686516e968692fe146a5c324c7f1fa83d2..530147609fe1e47320a1cbd9223ccdfb82ba7e7a 100644 --- a/paddle/fluid/operators/cholesky_op.cu +++ b/paddle/fluid/operators/cholesky_op.cu @@ -63,7 +63,6 @@ class CholeskyGPUKernel : public framework::OpKernel { for_range(matrix_band_part_functor); } - // TODO(guosheng): Add callback to check info auto info = memory::Alloc(dev_ctx, sizeof(int) * batch_count); auto* info_ptr = reinterpret_cast(info->ptr()); @@ -96,6 +95,20 @@ class CholeskyGPUKernel : public framework::OpKernel { #if CUDA_VERSION >= 9020 && !defined(_WIN32) } #endif + // check the info + std::vector error_info; // only for checking positive matrix + error_info.resize(batch_count); + + memory::Copy(platform::CPUPlace(), error_info.data(), + BOOST_GET_CONST(platform::CUDAPlace, dev_ctx.GetPlace()), + info_ptr, sizeof(int) * batch_count, dev_ctx.stream()); + + for (int i = 0; i < batch_count; ++i) { + PADDLE_ENFORCE_EQ(error_info[i], 0, + platform::errors::PreconditionNotMet( + "For batch [%d]: U(%d, %d) is zero, singular U.", i, + error_info[i], error_info[i])); + } } void Potrf(const platform::CUDADeviceContext& dev_ctx, cublasFillMode_t uplo, diff --git a/paddle/fluid/operators/cholesky_op.h b/paddle/fluid/operators/cholesky_op.h index b0280b00ecf447d36b199e6b6765fa7928e081f0..15dd8315362ed0221c5c8b9c523af37da38dfd7e 100644 --- a/paddle/fluid/operators/cholesky_op.h +++ b/paddle/fluid/operators/cholesky_op.h @@ -59,22 +59,24 @@ class CholeskyCPUKernel : public framework::OpKernel { Eigen::Matrix, Eigen::UpLoType::Upper> llt_decomposition(input); - PADDLE_ENFORCE_EQ( - llt_decomposition.info(), Eigen::Success, - platform::errors::InvalidArgument( - "Cholesky decomposition was not successful. The input matrice " - "might not be not be positive definite.")); + PADDLE_ENFORCE_EQ(llt_decomposition.info(), Eigen::Success, + platform::errors::InvalidArgument( + "Cholesky decomposition was not successful. The " + "%d-th input matrice " + "might not be not be positive definite.", + i)); output = llt_decomposition.matrixU(); } else { Eigen::LLT< Eigen::Matrix, Eigen::UpLoType::Lower> llt_decomposition(input); - PADDLE_ENFORCE_EQ( - llt_decomposition.info(), Eigen::Success, - platform::errors::InvalidArgument( - "Cholesky decomposition was not successful. The input matrice " - "might not be not be positive definite.")); + PADDLE_ENFORCE_EQ(llt_decomposition.info(), Eigen::Success, + platform::errors::InvalidArgument( + "Cholesky decomposition was not successful. The " + "%d-th input matrice " + "might not be not be positive definite.", + i)); output = llt_decomposition.matrixL(); } } diff --git a/python/paddle/fluid/tests/unittests/test_cholesky_op.py b/python/paddle/fluid/tests/unittests/test_cholesky_op.py index f3e6c079eedc8effc948a44e08a5dcdcae8d3081..ab08a0aacbf08768ffff43974ee9a7c7dd4a7288 100644 --- a/python/paddle/fluid/tests/unittests/test_cholesky_op.py +++ b/python/paddle/fluid/tests/unittests/test_cholesky_op.py @@ -100,5 +100,45 @@ class TestDygraph(unittest.TestCase): out = paddle.cholesky(x, upper=False) +class TestCholeskySingularAPI(unittest.TestCase): + def setUp(self): + self.places = [fluid.CPUPlace()] + if core.is_compiled_with_cuda(): + self.places.append(fluid.CUDAPlace(0)) + + def check_static_result(self, place, with_out=False): + with fluid.program_guard(fluid.Program(), fluid.Program()): + input = fluid.data(name="input", shape=[4, 4], dtype="float64") + result = paddle.cholesky(input) + + input_np = np.zeros([4, 4]).astype("float64") + + exe = fluid.Executor(place) + try: + fetches = exe.run(fluid.default_main_program(), + feed={"input": input_np}, + fetch_list=[result]) + except fluid.core.EnforceNotMet as ex: + print("The mat is singular") + pass + + def test_static(self): + for place in self.places: + self.check_static_result(place=place) + + def test_dygraph(self): + for place in self.places: + with fluid.dygraph.guard(place): + input_np = np.array([[[1, 2, 3], [4, 5, 6], [7, 8, 9]], + [[10, 11, 12], [13, 14, 15], + [16, 17, 18]]]).astype("float64") + input = fluid.dygraph.to_variable(input_np) + try: + result = paddle.cholesky(input) + except fluid.core.EnforceNotMet as ex: + print("The mat is singular") + pass + + if __name__ == "__main__": unittest.main()