Skip to content

Commit ce048de

Browse files
Aidyn-Apytorchmergebot
authored andcommitted
[ATen][CPU][Sparse] Use Third-Party Eigen for sparse add and addmm (pytorch#155357)
This pull request adds the following ops for sparse matrices using Eigen library: ```python add(a_csr, b_csr) add(a_csc, b_csc) addmm(c_csr, a_csr, b_csr) addmm(c_csr, a_csr, b_csc) addmm(c_csr, a_csc, b_csc) addmm(c_csr, a_csc, b_csr) addmm(c_csc, a_csr, b_csr) addmm(c_csc, a_csr, b_csc) addmm(c_csc, a_csc, b_csc) addmm(c_csc, a_csc, b_csr) ``` Currently, the operations for sparse matrices on CPU are available through MKL only. The non-existence of MKL on `aarch64` causes the unavailability of these ops on any machines with ARM based CPUs, including Apple Silicon, AWS Graviton and NVIDIA Grace. This PR addresses this issue by using Eigen as a backend for the above ops. This is a re-factored version of my previous PR pytorch#101814. The main difference with the old one, this does not enable Eigen by default. Pull Request resolved: pytorch#155357 Approved by: https://github.com/pearu, https://github.com/eqy
1 parent 90ea9cc commit ce048de

File tree

13 files changed

+423
-8
lines changed

13 files changed

+423
-8
lines changed

BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ header_template_rule(
279279
"@AT_BLAS_F2C@": "0",
280280
"@AT_BLAS_USE_CBLAS_DOT@": "1",
281281
"@AT_KLEIDIAI_ENABLED@": "0",
282+
"@AT_USE_EIGEN_SPARSE@": "0",
282283
},
283284
)
284285

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ option(USE_PRECOMPILED_HEADERS "Use pre-compiled headers to accelerate build."
289289
option(USE_PROF "Use profiling" OFF)
290290
option(USE_PYTORCH_QNNPACK "Use ATen/QNNPACK (quantized 8-bit operators)" ON)
291291
option(USE_SNPE "Use Qualcomm's SNPE library" OFF)
292+
option(USE_EIGEN_SPARSE "Use Eigen Sparse Matrices" OFF)
292293
option(USE_SYSTEM_EIGEN_INSTALL
293294
"Use system Eigen instead of the one under third_party" OFF)
294295
cmake_dependent_option(

aten/src/ATen/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ file(GLOB native_mkldnn_cpp "native/mkldnn/*.cpp")
9696
file(GLOB vulkan_cpp "vulkan/*.cpp")
9797
file(GLOB native_vulkan_cpp "native/vulkan/*.cpp" "native/vulkan/api/*.cpp" "native/vulkan/impl/*.cpp" "native/vulkan/ops/*.cpp")
9898

99+
file(GLOB native_eigen_cpp "native/sparse/eigen/*.cpp")
100+
99101
# Metal
100102
file(GLOB metal_h "metal/*.h")
101103
file(GLOB metal_cpp "metal/*.cpp")
@@ -341,6 +343,9 @@ if(USE_VULKAN)
341343
else()
342344
set(all_cpu_cpp ${all_cpu_cpp} ${vulkan_cpp})
343345
endif()
346+
if(USE_EIGEN_SPARSE)
347+
set(all_cpu_cpp ${all_cpu_cpp} ${native_eigen_cpp})
348+
endif()
344349

345350
if(USE_MTIA)
346351
set(ATen_MTIA_SRCS ${ATen_MTIA_SRCS} ${mtia_cpp} ${mtia_h} ${native_mtia_cpp} ${native_mtia_h})

aten/src/ATen/Config.h.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@
2020
#define AT_BLAS_F2C() @AT_BLAS_F2C@
2121
#define AT_BLAS_USE_CBLAS_DOT() @AT_BLAS_USE_CBLAS_DOT@
2222
#define AT_KLEIDIAI_ENABLED() @AT_KLEIDIAI_ENABLED@
23+
#define AT_USE_EIGEN_SPARSE() @AT_USE_EIGEN_SPARSE@

aten/src/ATen/Context.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,14 @@ bool Context::hasLAPACK() {
698698
#endif
699699
}
700700

701+
bool Context::hasEigenSparse() {
702+
#if AT_USE_EIGEN_SPARSE()
703+
return true;
704+
#else
705+
return false;
706+
#endif
707+
}
708+
701709
at::QEngine Context::qEngine() const {
702710
static auto _quantized_engine = []() {
703711
at::QEngine qengine = at::kNoQEngine;

aten/src/ATen/Context.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ class TORCH_API Context {
133133
static bool hasLAPACK();
134134
static bool hasMKLDNN();
135135
static bool ckSupported();
136+
static bool hasEigenSparse();
136137
static bool hasMAGMA() {
137138
return detail::getCUDAHooks().hasMAGMA();
138139
}
@@ -615,6 +616,10 @@ inline bool hasLAPACK() {
615616
return globalContext().hasLAPACK();
616617
}
617618

619+
inline bool hasEigenSparse() {
620+
return globalContext().hasEigenSparse();
621+
}
622+
618623
inline bool hasMAGMA() {
619624
return globalContext().hasMAGMA();
620625
}

aten/src/ATen/native/sparse/SparseBlasImpl.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
#include <ATen/Parallel.h>
2424
#endif
2525

26+
#if AT_USE_EIGEN_SPARSE()
27+
#include <ATen/native/sparse/eigen/SparseBlasImpl.h>
28+
#endif
2629

2730
namespace at::native::sparse::impl {
2831

@@ -442,13 +445,15 @@ void add_out_sparse_csr(
442445
const Tensor& mat2,
443446
const Scalar& alpha,
444447
const Tensor& result) {
445-
#if !AT_MKL_ENABLED()
446-
TORCH_CHECK(
447-
false,
448-
"Calling add on a sparse CPU tensor requires compiling PyTorch with MKL. ",
449-
"Please use PyTorch built MKL support.");
450-
#else
448+
#if AT_USE_MKL_SPARSE()
451449
sparse::impl::mkl::add_out_sparse_csr(mat1, mat2, alpha, result);
450+
#elif AT_USE_EIGEN_SPARSE()
451+
sparse::impl::eigen::add_out_sparse(mat1, mat2, alpha, result);
452+
#else
453+
TORCH_CHECK(
454+
false,
455+
"Calling add on a sparse CPU tensor requires compiling PyTorch with MKL. ",
456+
"Please use PyTorch built MKL support.");
452457
#endif
453458
}
454459

@@ -459,7 +464,7 @@ void triangular_solve_out_sparse_csr(
459464
bool upper,
460465
bool transpose,
461466
bool unitriangular) {
462-
#if !AT_MKL_ENABLED()
467+
#if !AT_USE_MKL_SPARSE()
463468
TORCH_CHECK(
464469
false,
465470
"Calling triangular_solve on a sparse CPU tensor requires compiling PyTorch with MKL. ",

aten/src/ATen/native/sparse/SparseCsrTensorMath.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@
127127
#include <ATen/ops/zeros_like.h>
128128
#endif
129129

130+
#if AT_USE_EIGEN_SPARSE()
131+
#include <ATen/native/sparse/eigen/SparseBlasImpl.h>
132+
#endif
133+
130134
#include <algorithm>
131135

132136
namespace at {
@@ -536,7 +540,12 @@ static void addmm_out_sparse_csr_native_cpu(
536540
auto values = sparse.values();
537541

538542
scalar_t cast_alpha = alpha.to<scalar_t>();
539-
r.mul_(beta);
543+
// If beta is zero NaN and Inf should not be propagated to the result
544+
if (beta.toComplexDouble() == 0.) {
545+
r.zero_();
546+
} else {
547+
r.mul_(beta);
548+
}
540549
AT_DISPATCH_INDEX_TYPES(
541550
col_indices.scalar_type(), "csr_mm_crow_indices", [&]() {
542551
auto csr_accessor = csr.accessor<index_t, 1>();
@@ -648,6 +657,15 @@ Tensor& addmm_out_sparse_compressed_cpu(
648657
return result;
649658
}
650659

660+
#if AT_USE_EIGEN_SPARSE()
661+
if ((result.layout() == kSparseCsr || result.layout() == kSparseCsc) &&
662+
(mat1.layout() == kSparseCsr || mat1.layout() == kSparseCsc) &&
663+
(mat2.layout() == kSparseCsr || mat2.layout() == kSparseCsc)) {
664+
sparse::impl::eigen::addmm_out_sparse(mat1, mat2, result, alpha, beta);
665+
return result;
666+
}
667+
#endif
668+
651669
#if !AT_USE_MKL_SPARSE()
652670
// The custom impl addmm_out_sparse_csr_native_cpu only supports CSR @
653671
// strided -> strided

0 commit comments

Comments
 (0)