【免费下载链接】ops-sparse本项目是CANN提供的高性能稀疏矩阵计算的算子库专注于优化稀疏矩阵的计算效率。项目地址: https://gitcode.com/cann/ops-sparsename: sparse-ST-develop description: ops-sparse 稀疏算子测试开发规范定义测试框架结构、单层 Eigen golden 参考、NPU 封装、验证逻辑等。Sparse ST 测试开发规范测试标杆体系单层 Eigen Golden使用Eigen SparseMatrix作为唯一 CPU golden 参考┌─────────────────────────────┐ │ NPU 算子执行 │ └──────────┬──────────────────┘ │ NPU 结果 ▼ ┌─────────────────────────────┐ │ 精度验证 │ └──────────┬──────────────────┘ │ ┌──────────▼──────────────────┐ │ Eigen Golden (FP64) │ │ 唯一 CPU 参考基准 │ └─────────────────────────────┘实现用途依赖Eigen SparseMatrix唯一 CPU golden 参考与 cuSPARSE 结果对齐Eigen3 (header-only)Eigen 作为测试标杆的原因C 原生与测试代码同语言无需跨语言调用header-only无复杂构建依赖CANN SDK 通常自带SparseMatrix (CSR)直接对应 cuSPARSE 的 CSR 格式语义对齐社区公认广泛使用的科学计算库精度可复现FP64 精度使用double计算避免精度损失作为可靠基准测试框架ops-sparse 使用自定义测试框架非 GTest测试代码结构遵循本 SKILL 中定义的规范模板。 公共测试基础设施位于test/frame/每个算子开发必须优先复用这些公共头文件。公共头文件test/frame/头文件职责types.hPrecisionMode枚举ABS/REL/MERE_MARE/EXACT/INTEGERVerifyConfig精度配置 CaseSummary统计verify.hVerifier精度比对类策略模式AbsStrategy / RelStrategy / MereMareStrategy / ExactStrategy / IntegerStrategyfill.hSparseFillGeneratorCsrMatrix/CooMatrix/CscMatrix结构体 makeSparseCsr/Coo/Csc/makeDense/ makeDenseFloat/makeDiagCsr/makeEmptyCsr快速填充函数descriptor_manager.hGeneric 描述符 RAII 封装SpMatManager/DnVecManager/DnMatManager/HandleManager/DeviceBuffer自动 Create/Destroysparse_test.hAclEnvScopeRAII 环境初始化 SparseTestParamBase参数结构体基类 aclDataTypeOfT()模板 SPARSE_CHECK_RET/SPARSE_LOG宏csv_loader.hcsv_map/ReadMap/GetCasesFromCsvParamType/parseBool/parseInt/parseFloat等 CSV 解析器强制规则所有新算子测试必须使用test/frame/公共头文件禁止在算子测试代码中重新定义相同功能精度配置必须使用VerifyConfigVerifier禁止手写Verify()函数描述符生命周期必须使用 RAII ManagerHandle/SpMat/DnVec/DnMat禁止裸指针手动 destroyACL 环境初始化必须使用AclEnvScope禁止手写 Init/Finalize若新增通用功能必须先补充到test/frame/对应头文件再在算子测试中调用算子级文件每个算子独立文件职责位置{op}_param.h参数结构体继承SparseTestParamBase实现fillCustom()caseId()test/{op}/{op}_golden.hCPU golden 参考实现使用 Eigen SparseMatrix FP64test/{op}/{op}_npu_wrapper.hNPU 封装描述符创建/销毁、kernel 调用、D2H 拷贝test/{op}/archXX/{op}_test.cppGTest 入口::testing::TestWithParam{Op}ParamTEST_Ptest/{op}/archXX/{op}_test.csvCSV 用例表列名API 参数名test/{op}/archXX/每个算子新增时必须在test/{op}/下创建{op}_param.h{op}_golden.h在test/{op}/archXX/下创建{op}_npu_wrapper.h{op}_test.cpp{op}_test.csv。算子交付清单新算子GTest CSV 模式spmv/spmm 除外test/{op_name}/ ├── CMakeLists.txt # 使用 ops_sparse_add_gtest_tests 宏注册算子 ├── README.md # 算子测试说明算子描述 测试覆盖情况 编译运行 ├── {op_name}_param.h # 参数结构体继承 SparseTestParamBase ├── {op_name}_golden.h # CPU golden 参考Eigen SparseMatrixdouble FP64 └── archXX/ ├── {op_name}_npu_wrapper.h # NPU 封装描述符创建/销毁、kernel 调用、D2H 拷贝 ├── {op_name}_test.cpp # GTest 测试入口禁止定义 main 函数 └── {op_name}_test.csv # CSV 用例表基础列 算子自定义列新算子交付标准{op_name}_param.h参数结构体继承SparseTestParamBasecsv_loader.h实现fillCustom()caseId(){op_name}_golden.h实现完整使用 Eigen SparseMatrix FP64 避免精度损失{op_name}_npu_wrapper.h使用 RAII ManagerHandle/SpMat/DnVec/DnMat/DeviceBuffer禁止裸指针{op_name}_test.cpp使用test/frame/公共头文件禁止手写 Verify / Init / descriptor destroy{op_name}_test.cpp使用::testing::TestWithParamParamTypeTEST_P禁止定义 main 函数{op_name}_test.csv含基础列m, n, sparsity, empty_row_prob, seed, expect_result 算子自定义列CMakeLists.txt 通过ops_sparse_add_gtest_tests({op_name} ${OPS_SPARSE})注册不是ops_sparse_add_test编译通过bash build.sh --ops{op_name}ST 通过./{op_name}_test --gtest_filter*至少一个用例可执行老算子仅 spmv / spmm保持现状test/{op_name}/ ├── CMakeLists.txt # 使用 ops_sparse_add_test 宏注册算子 ├── README.md # 算子测试说明 └── archXX/ └── {op_name}_test.cpp # 自定义 main TestRegistry 统计老算子交付标准TestRegistry统计通过/失败用例CMakeLists.txt 通过ops_sparse_add_test({op_name} ${OPS_SPARSE})注册编译通过bash build.sh --ops{op_name}ST 通过bash build.sh --ops{op_name} --run测试代码组织强制新算子新算子测试入口必须使用 GTest CSV 参数化 test/frame/框架典型结构#include gtest/gtest.h #include sparse_test.h #include csv_loader.h #include fill.h #include verify.h #include ../spmv_param.h #include ../spmv_golden.h #include spmv_npu_wrapper.h #include acl/acl.h #include cann_ops_sparse.h using namespace sparse_test; // 1. GTest 测试夹具 class SpMVTest : public ::testing::TestWithParamSpMVParam { public: static void SetUpTestSuite() { env_ std::make_uniqueAclEnvScope(); spHandle_ std::make_uniqueHandleManager(); spHandle_-setStream(env_-stream()); } static void TearDownTestSuite() { spHandle_.reset(); env_.reset(); } protected: inline static std::unique_ptrAclEnvScope env_; inline static std::unique_ptrHandleManager spHandle_; }; // 2. TEST_P 测试用例 TEST_P(SpMVTest, GenericSuccess) { auto p GetParam(); PrintCaseInfoString(p); // 期望成功的用例 ASSERT_EQ(p.expect_result, ACL_SPARSE_STATUS_SUCCESS); // 1. 生成 CSR 数据使用框架 fill.h auto csr makeSparseCsr(p.m, p.n, p.sparsity, p.seed); auto xVec makeDenseFloat(p.n, -5.0, 10.0, p.seed 1); auto yInit makeDenseFloat(p.m, -5.0, 10.0, p.seed 2); // 2. Eigen golden 作为唯一比对基准 auto yGolden SpMVGolden(csr, xVec, yInit, p.alpha, p.beta, p.transpose); // 3. NPU 调用使用 npu_wrapper.h 封装 auto yNpu SpMVNpuWrapper(*spHandle_, env_-stream(), csr, xVec, yInit, p.alpha, p.beta, p.transpose, p.compute_type); // 4. 精度比对使用框架 verify.h阈值从 CSV 读取 VerifyConfig cfg; cfg.SetMode(PrecisionMode::MERE_MARE) .SetMERE(p.mere_threshold) .SetMARE(p.mare_multiplier * p.mere_threshold); EXPECT_TRUE(Verifier::verifyVector(yNpu, yGolden, cfg, p.caseId())); } // 3. 参数化实例化从 CSV 加载用例 INSTANTIATE_TEST_SUITE_P( SpMV, SpMVTest, ::testing::ValuesIn(GetCasesFromCsvSpMVParam(spmv_test.csv)), [](https://gitcode.com/cann/ops-sparse/blob/b4e21135ac3c9b644f93b08e7845b913668c1616/agent/skills/sparse-ST-develop/const ::testing::TestParamInfoSpMVParam info?utm_sourcegitcode_repo_files) { return info.param.caseId(); } ); // 禁止定义 main 函数由 test/frame/test_main.cpp 提供Null Handle / 异常路径测试TEST_F 模式对于 null handle、invalid descriptor 等异常路径测试使用TEST_F而非TEST_P不下 CSVclass SpMVExceptionTest : public ::testing::Test { protected: void SetUp() override { env_ std::make_uniqueAclEnvScope(); spHandle_ std::make_uniqueHandleManager(); spHandle_-setStream(env_-stream()); } void TearDown() override { spHandle_.reset(); env_.reset(); } std::unique_ptrAclEnvScope env_; std::unique_ptrHandleManager spHandle_; }; TEST_F(SpMVExceptionTest, NullHandle) { // 传入 nullptr handle期望返回 ACL_SPARSE_STATUS_HANDLE_IS_NULLPTR auto ret aclsparseSpMV(nullptr, ACL_SPARSE_OP_NON_TRANSPOSE, alpha, matA.cget(), vecX.cget(), beta, vecY.get(), ACL_FLOAT, ACL_SPARSE_SPMV_ALG_DEFAULT, nullptr); EXPECT_EQ(ret, ACL_SPARSE_STATUS_HANDLE_IS_NULLPTR); } TEST_F(SpMVExceptionTest, InvalidSpMatDescr) { // 传入 nullptr matA期望返回 ACL_SPARSE_STATUS_INVALID_VALUE auto ret aclsparseSpMV(spHandle_-get(), ACL_SPARSE_OP_NON_TRANSPOSE, alpha, nullptr, vecX.cget(), beta, vecY.get(), ACL_FLOAT, ACL_SPARSE_SPMV_ALG_DEFAULT, nullptr); EXPECT_EQ(ret, ACL_SPARSE_STATUS_INVALID_VALUE); } TEST_F(SpMVExceptionTest, NullDnVec) { // 传入 nullptr vecX期望返回 ACL_SPARSE_STATUS_INVALID_VALUE auto ret aclsparseSpMV(spHandle_-get(), ACL_SPARSE_OP_NON_TRANSPOSE, alpha, matA.cget(), nullptr, beta, vecY.get(), ACL_FLOAT, ACL_SPARSE_SPMV_ALG_DEFAULT, nullptr); EXPECT_EQ(ret, ACL_SPARSE_STATUS_INVALID_VALUE); }测试代码组织老算子仅 spmv / spmm老算子保留自定义 main TestRegistry 统计模式典型结构#include sparse_test.h #include fill.h #include verify.h #include descriptor_manager.h #include acl/acl.h #include cann_ops_sparse.h using namespace sparse_test; static bool TestSpmv(const char* caseName, int64_t m, int64_t n, double sparsity, float alpha, float beta, bool trans, aclrtStream stream) { std::cout caseName m m n n sp sparsity alpha alpha beta beta \n; // 1. 生成 CSR 数据使用框架 fill.h auto csr makeSparseCsr(m, n, sparsity, 42); auto xVec makeDenseFloat(n, -5.0, 10.0, 100); auto yInit makeDenseFloat(m, -5.0, 10.0, 101); // 2. 自写 CPU golden老算子保留 auto yGolden SpmvCpu(csr, xVec, yInit, alpha, beta, trans); // 4. Device 内存RAII auto dRowPtr DeviceBuffer::copyFrom(csr.rowOffsets.data(), csr.rowOffsets.size() * sizeof(int32_t)); auto dColIdx DeviceBuffer::copyFrom(csr.colIndices.data(), csr.colIndices.size() * sizeof(int32_t)); auto dVals DeviceBuffer::copyFrom(csr.values.data(), csr.values.size() * sizeof(float)); auto dX DeviceBuffer::copyFrom(xVec.data(), xVec.size() * sizeof(float)); auto dY DeviceBuffer::copyFrom(yInit.data(), yInit.size() * sizeof(float)); // 5. 描述符RAII HandleManager handle; handle.setStream(stream); SpMatManager matA SpMatManager::createConstCsr(m, n, csr.nnz, dRowPtr.get(), dColIdx.get(), dVals.get()); DnVecManager vecX DnVecManager::createConst(n, dX.get(), ACL_FLOAT); DnVecManager vecY DnVecManager::create(m, dY.get(), ACL_FLOAT); // 6. 算子调用 auto op trans ? ACL_SPARSE_OP_TRANSPOSE : ACL_SPARSE_OP_NON_TRANSPOSE; auto ret aclsparseSpMV(handle.get(), op, alpha, matA.cget(), vecX.cget(), beta, vecY.get(), ACL_FLOAT, ACL_SPARSE_SPMV_ALG_DEFAULT, nullptr); SPARSE_CHECK_RET(ret ACL_SPARSE_STATUS_SUCCESS, return false); SPARSE_CHECK_RET(aclrtSynchronizeStream(stream) ACL_SUCCESS, return false); // 7. D2H std::vectorfloat yNpu(m); dY.copyToHost(yNpu.data(), yNpu.size() * sizeof(float)); // 8. 精度比对使用框架 verify.h VerifyConfig cfg; cfg.SetMode(PrecisionMode::MERE_MARE).SetMERE(0.0001220703125).SetMARE(10.0); return Verifier::verifyVector(yNpu, yGolden, cfg, std::string(caseName)); } int main() { AclEnvScope env; TestRegistry reg; reg.record(spmv-f32-default, TestSpmv(default-f32, 512, 1024, 0.9, 1.0f, 0.0f, false, env.stream())); // ... 更多用例 ... reg.printSummary(); return reg.failCount() 0 ? 0 : 1; }Eigen Golden 参考实现每个算子必须在test/{op_name}/{op_name}_golden.h中实现 Eigen golden 参考。以下是 SpMV / SpMM 样例新增算子时可参照其 API 形状。SpMV Eigen GoldenCSR 格式// test/{op_name}/{op_name}_golden.h #pragma once #include Eigen/Eigen #include Eigen/SparseCore #include ../frame/fill.h namespace sparse_test { // SpMV 的 Eigen golden 实现 // 使用 Eigen::SparseMatrixdouble FP64 作为唯一 CPU 参考基准 template typename T std::vectorT SpMVGolden( const CsrMatrix csr, const std::vectorT x, const std::vectorT yInit, T alpha, T beta, bool transpose) { using Scalar double; // Eigen 用 FP64 避免精度损失 int rows static_castint(csr.rows); int cols static_castint(csr.cols); int nnz static_castint(csr.nnz); // 1. 构建 Eigen SparseMatrixCSR RowMajor Eigen::SparseMatrixScalar, Eigen::RowMajor A(rows, cols); std::vectorEigen::TripletScalar triplets; triplets.reserve(nnz); for (int i 0; i rows; i) { for (int j csr.rowOffsets[i]; j csr.rowOffsets[i 1]; j) { triplets.emplace_back(i, csr.colIndices[j], static_castScalar(csr.values[j])); } } A.setFromTriplets(triplets.begin(), triplets.end()); // 2. 构建 Eigen Vector转换为 FP64 Eigen::VectorXd xVec(cols), yVec(rows); for (int i 0; i cols; i) xVec(i) static_castScalar(x[i]); for (int i 0; i rows; i) yVec(i) static_castScalar(yInit[i]); // 3. 稀疏矩阵-向量乘法 Eigen::VectorXd result; if (transpose) { result alpha * (A.transpose() * xVec) beta * yVec; } else { result alpha * (A * xVec) beta * yVec; } // 4. 转换回 T 类型 std::vectorT output(rows); for (int i 0; i rows; i) { output[i] static_castT(result(i)); } return output; } } // namespace sparse_testSpMM Eigen Golden// test/{op_name}/{op_name}_golden.h (SpMM 部分) namespace sparse_test { // SpMM 的 Eigen golden 实现C alpha * A * B beta * C // A: sparse (m x k, CSR), B: dense (k x n), C: dense (m x n) template typename T std::vectorT SpMMGolden( const CsrMatrix A, const std::vectorT B, const std::vectorT C_init, int k, int n, T alpha, T beta, bool rowMajorB, bool rowMajorC) { using Scalar double; int m static_castint(A.rows); // 1. 构建 Eigen SparseMatrix Eigen::SparseMatrixScalar, Eigen::RowMajor Amat(m, k); std::vectorEigen::TripletScalar triplets; for (int i 0; i m; i) for (int j A.rowOffsets[i]; j A.rowOffsets[i 1]; j) triplets.emplace_back(i, A.colIndices[j], static_castScalar(A.values[j])); Amat.setFromTriplets(triplets.begin(), triplets.end()); // 2. 构建 Eigen DenseMatrix转换为 FP64 Eigen::MatrixXd Bmat(k, n), Cmat(m, n); for (int r 0; r k; r) for (int c 0; c n; c) Bmat(r, c) rowMajorB ? B[r * n c] : B[r c * k]; for (int r 0; r m; r) for (int c 0; c n; c) Cmat(r, c) rowMajorC ? C_init[r * n c] : C_init[r c * m]; // 3. 稀疏矩阵-稠密矩阵乘法 Cmat alpha * (Amat * Bmat) beta * Cmat; // 4. 转换回 T 类型 std::vectorT output(m * n); for (int r 0; r m; r) for (int c 0; c n; c) { if (rowMajorC) output[r * n c] static_castT(Cmat(r, c)); else output[r c * m] static_castT(Cmat(r, c)); } return output; } } // namespace sparse_test测试用例执行函数完整流程该示例已在上方测试代码组织章节给出使用test/frame/框架makeSparseCsr/DeviceBuffer/SpMatManager/Verifier/AclEnvScope。下方不再重复。NPU 封装规范新算子测试必须使用框架 RAII Manager禁止裸指针手写aclrtMalloc / aclrtFree / aclsparseDestroy*。Generic API使用 RAII通过test/frame/descriptor_manager.h的HandleManager/SpMatManager/DnVecManager/DnMatManager/DeviceBuffer自动管理生命周期{ // Device 内存自动释放 auto dRowPtr DeviceBuffer::copyFrom(csr.rowOffsets.data(), ...); auto dVals DeviceBuffer::copyFrom(csr.values.data(), ...); // 描述符自动 Destroy HandleManager handle; handle.setStream(stream); auto matA SpMatManager::createConstCsr(m, n, nnz, dRowPtr.get(), ...); auto vecX DnVecManager::createConst(n, dX.get(), ACL_FLOAT); auto vecY DnVecManager::create(m, dY.get(), ACL_FLOAT); // 算子调用 aclsparseSpMV(handle.get(), op, alpha, matA.cget(), vecX.cget(), beta, vecY.get(), ACL_FLOAT, ACL_SPARSE_SPMV_ALG_DEFAULT, nullptr); // D2H std::vectorfloat yNpu(m); dY.copyToHost(yNpu.data(), ...); } // exit scope → 自动 DestroyLegacy API使用 DeviceBuffer HandleManagerLegacy API 无 SpMatDescr/DnVec/DnMat 描述符使用DeviceBuffer管理内存HandleManager管理 handle{ auto dDl DeviceBuffer::copyFrom(dl.data(), (m - 1) * sizeof(float)); auto dD DeviceBuffer::copyFrom(d.data(), m * sizeof(float)); auto dDu DeviceBuffer::copyFrom(du.data(), (m - 1) * sizeof(float)); auto dX DeviceBuffer::copyFrom(xHost.data(), m * nrhs * sizeof(float)); HandleManager handle; handle.setStream(stream); // Legacy 算子可能需要 MatDescr手动创建/销毁因 ops-sparse 当前未封装 // aclsparseMatDescr_t matDescr; // aclsparseCreateMatDescr(matDescr); // ... aclsparseSetMatType / aclsparseSetMatIndexBase ... // aclsparseDestroyMatDescr(matDescr); aclsparseSgtsv2(handle.get(), m, dDl.get(), dD.get(), dDu.get(), dX.get(), nrhs, m, bufferSize); aclrtSynchronizeStream(stream); std::vectorfloat xNpu(m * nrhs); dX.copyToHost(xNpu.data(), xNpu.size() * sizeof(float)); VerifyConfig cfg; cfg.SetMode(PrecisionMode::MERE_MARE).SetMERE(0.0001220703125).SetMARE(10.0); Verifier::verifyVector(xNpu, xGolden, cfg, caseName); }Legacy API 注意事项每种精度版本独立测试Legacy API 同一算子可能同时提供 S/D 版本必须分别测试无需 Generic 描述符不存在 SpMatDescr 创建/销毁但 MatDescr 若接口要求则必须创建手动管理workspace 处理部分 Legacy 算子通过输入参数pBufferSize返回大小输入输出语义需注意错误处理所有步骤任一步骤失败RAII 自动清理DeviceBuffer 析构时释放、HandleManager 析构时 destroyCMakeLists.txt 模板新算子GTest CSV 模式spmv/spmm 除外每个新算子的test/{op_name}/CMakeLists.txt只需一行ops_sparse_add_gtest_tests({op_name} ${OPS_SPARSE})ops_sparse_add_gtest_tests宏位于cmake/test.cmake自动链接 GTest test/frame/test_main.cpp共享 main 入口自动包含test/frame/作为 include 路径自动查找test/{op_name}/archXX/{op_name}_test.cpp按 SOC_ARCH_DIRS 匹配自动拷贝test/{op_name}/archXX/{op_name}_test.csv到 build 目录默认启用 Eigengolden 参考可通过TEST_USE_EIGENOFF关闭老算子仅 spmv / spmm保持现状ops_sparse_add_test({op_name} ${OPS_SPARSE})ops_sparse_add_test宏位于cmake/test.cmake自动包含test/frame/作为 include 路径自动查找test/{op_name}/archXX/{op_name}_test.cpp按 SOC_ARCH_DIRS 匹配不链接 GTest不链接共享 test_main.cppEigen 精度容差规范由于 Eigen 使用 FP64 计算NPU 使用 T 类型不同 dtype 的容差不同NPU dtypeEigen golden rtolEigen golden atol说明FP321e-51e-5FP32 标准FP161e-31e-3FP16 标准BF165e-35e-3BF16 标准INT320 (位精确)0整数计算测试用例设计指南L0 用例基础功能验证Shapennzdtype格式说明4×48FP32CSR基本方阵8×1624FP32CSR宽矩阵16×824FP32CSR高矩阵L1 用例覆盖 边界 大 shapeShapennzdtype格式说明2048×204832768FP32CSR大 shape1×10010FP32CSR单行100×110FP32CSR单列10×100FP32CSR空矩阵64×64128FP16CSR半精度64×64128FP32CSR(T)转置常见问题排查问题症状解决方案Eigen header 找不到编译报错fatal error: Eigen/Eigen: No such file or directory检查 CMake 是否启用TEST_USE_EIGENON确认 Eigen3 已安装find_package(Eigen3 3.3)若无需 Eigen 可设TEST_USE_EIGENOFFCSV 路径错误运行时报错ReadMap: cannot open xxx_test.csv确认 CSV 文件已拷贝到 build 目录ops_sparse_add_gtest_tests宏自动处理检查相对路径是否正确gtest_main冲突链接报错multiple definition of main确认{op}_test.cpp中没有定义main()函数由test/frame/test_main.cpp提供描述符泄漏运行结束后内存泄漏警告检查所有aclsparseCreate*是否有配对的aclsparseDestroy*推荐使用 RAII ManagerSpMatManager/DnVecManager/DnMatManagerRAII 双重释放运行崩溃double free or corruption检查是否同时使用了 RAII Manager 和手动aclsparseDestroy*二者只能选其一arch 目录不匹配CMake 报错test arch archXX has no matching src确认SOC_VERSION与SOC_ARCH_DIRS匹配检查src/{op}/archXX/和test/{op}/archXX/目录是否存在fill/golden 不匹配精度验证失败golden 结果与预期不符检查fill.h生成的数据格式是否与golden.h期望的输入格式一致如 CSR vs COO精度 failVerifier::verifyVector返回 false检查VerifyConfig的精度模式和阈值是否合理对比 NPU 输出与 golden 的最大误差位置参考ops-precision-standard技能稀疏格式不支持算子返回ACL_SPARSE_STATUS_NOT_SUPPORTED检查传入的稀疏格式CSR/COO/CSC是否被算子支持参考算子文档或cann_ops_sparse.h中的格式枚举null handlespHandle_为空测试崩溃Segmentation fault检查SetUp()中spHandle_是否成功创建确认HandleManager构造未抛异常【免费下载链接】ops-sparse本项目是CANN提供的高性能稀疏矩阵计算的算子库专注于优化稀疏矩阵的计算效率。项目地址: https://gitcode.com/cann/ops-sparse创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考