CuPy GPU 稀疏矩阵与稀疏数组完全指南:cupyx.scipy.sparse 用法、索引 dtype 与底层 cuSPARSE 实现
CuPy GPU 稀疏矩阵与稀疏数组完全指南cupyx.scipy.sparse 用法、索引 dtype 与底层 cuSPARSE 实现【免费下载链接】cupyNumPy SciPy for GPU项目地址: https://gitcode.com/GitHub_Trending/cu/cupyCuPy 在cupyx.scipy.sparse中提供了与 SciPy 稀疏模块 API 高度兼容的 GPU 稀疏数组/矩阵包数据与运算全部驻留在显存中底层调用 NVIDIA cuSPARSE 完成高性能稀疏线性代数。本文以官方参考文档 docs/source/reference/scipy_sparse.rst 为主体结合cupyx/scipy/sparse目录下的源码实现系统讲解 CuPy 稀疏对象的支持格式、int32/int64 索引 dtype 的自动选择规则、与 SciPy/CuPy 稠密数组的转换方式、已知限制以及完整 API 导览帮助你正确、高效地在 GPU 上处理稀疏数据。模块概览与 SciPy 对齐的 GPU 稀疏线性代数cupyx.scipy.sparse是 CuPy 的稀疏数组包专用于数值型稀疏数据其 API 设计与scipy.sparse保持一致使用方式可参考 SciPy 官方稀疏模块文档。两者的核心差异在于CuPy 稀疏对象建立在cuSPARSE之上用于在 GPU 上执行高性能稀疏线性代数运算而数据始终保存在显存中。模块入口为 cupyx/scipy/sparse/init.py它集中导出了全部公开 API从源码注释可以看出 CuPy 明确列出的未实现清单bsr_array/bsr_matrix分块稀疏行 Block Sparse Rowdok_array/dok_matrix字典键 Dictionary of Keyslil_array/lil_matrix链表 List of Lists对应的isspmatrix_bsr/isspmatrix_lil/isspmatrix_dok判定函数save_npz/load_npz磁盘读写expand_dims展开维度需要 n-D 稀疏数组支持推荐使用 sparse array*_array类CuPy 中的稀疏数组类较新遵循 NumPy 语义——*表示逐元素乘法矩阵乘法使用。SciPy 计划逐步弃用稀疏矩阵*_matrix转而推广稀疏数组CuPy 将跟随这一趋势。迁移旧代码时可参考 SciPy 官方的 Migration from spmatrix to sparray 迁移指南。CuPy 与 SciPy 的差异清单支持的存储格式仅 COO、CSR、CSC、DIACuPy 只实现了四种格式对应四个格式类每个都有 array 与 matrix 两种变体格式类array / matrix说明COOcoo_array/coo_matrix坐标格式用row、col坐标数组存储CSRcsr_array/csr_matrix压缩稀疏行按行压缩多数运算的首选格式CSCcsc_array/csc_matrix压缩稀疏列按列压缩DIAdia_array/dia_matrix对角格式用offsets与对角数据存储不支持的格式包括 SciPy 中的 BSR、DOK、LIL。这一点在 cupyx/scipy/sparse/init.py 的注释中有明确说明。维度2-D 为主COO 与 CSR 额外支持 1-D所有格式都支持二维2-D其中coo_array与csr_array还额外支持一维1-D。CuPy 没有 n-D多维稀疏数组支持因此不存在expand_dims函数。这一约束也体现在工具函数中cupyx/scipy/sparse/_sputils.py 的check_shape默认仅接受allow_nd(2,)二维仅在显式传入(1, 2)时才允许一维形状。数据 dtype仅 cuSPARSE 支持的 5 种CuPy 稀疏对象的data数组仅支持以下 dtype与 cuSPARSE 支持的类型严格对应boolfloat32float64complex64complex128这一约束在 cupyx/scipy/sparse/_sputils.py 中有源码级印证第 13-14 行定义了_SPARSE_DATA_KINDS frozenset(?fdFD)?bool、ffloat32、dfloat64、Fcomplex64、Dcomplex128is_sparse_data_dtype函数正是据此判断一个 dtype 能否作为稀疏data数组存储。SciPy 除此之外还支持整数 dtype 以及扩展精度的longdouble/clongdouble这是 CuPy 与 SciPy 的重要差异。save_npz / load_npz 未实现save_npz/load_npz在 CuPy 稀疏模块中未实现需要持久化稀疏数据时请自行转换例如通过下文介绍的.get()转为 SciPy 对象后使用 SciPy 的 NPZ 接口或自行保存原始data/indices/indptr数组。索引 dtype 自动选择int32 与 int64 的规则与 SciPy 相同CuPy 稀疏对象会根据矩阵维度和索引值自动选择索引数组indices、indptr、row、col的 dtypeint32当所有索引值和维度都能放进 32 位整数时常见情况int64当任意维度或索引值超过2**31 - 1时。该 dtype 由cupyx.scipy.sparse.get_index_dtype计算得出镜像 SciPy 的逻辑并在格式转换、算术运算和索引操作中保持不变。查看 cupyx/scipy/sparse/_sputils.py 的实现可以发现其判定流程若传入的maxval大于int32max2**31 - 1直接选择 int64逐个检查传入的索引数组若数组 dtype 无法安全转换can_cast失败为 int32则选择 int64若设置了check_contentsTrue还会进一步检查数组内容——只有当实际maxval/minval越界时才升级为 int64否则保持 int32。同时SciPy 语义也被完整继承稀疏array的构造函数会保留你传入的索引数组 dtype而稀疏matrix的构造函数在数值放得下时可能将 int64 索引降级为 int32。相关辅助函数safely_cast_index_arrays见 cupyx/scipy/sparse/_sputils.py专门负责检查A.shape是否适合降级并返回转换后的索引数组当需要降级时返回新数组否则原样返回可通过A.indptr is new_indptr判断是否发生了降级。底层 dispatchGeneric API 与 int32-only 回退从文档与源码看委托给 cuSPARSE 的运算遵循两条路径Generic APISpMatDescrint64 索引优先走 cuSPARSE 通用接口这类接口原生支持 int64纯 CuPy 回退对于仅支持 int32 的旧版 API如csr2cscEx2、xcoo2csr、csrgeam2由 CuPy 内部实现回退逻辑。已知限制仅支持 int32 的操作以下三个cupyx.scipy.sparse.linalg下的操作仅支持 int32 索引当传入 int64 索引的稀疏对象时会抛出ValueError。原因都是底层 cuSPARSE/cuSOLVER 例程没有 int64 重载函数底层例程说明cupyx.scipy.sparse.linalg.spsolvecusolverSptcsrlsvqr该例程无 int64 重载见 cupyx/scipy/sparse/linalg/_solve.py其中通过cusparse._check_int32_indices(A, spsolve)强制校验cupyx.scipy.sparse.linalg.spilucusparsetcsrilu02该例程无 int64 重载见 cupyx/scipy/sparse/linalg/_solve.py 的csrilu02调用cupyx.scipy.sparse.linalg.spsolve_triangularCUDA 12.0 以下回退到cusparsetcsrsm2CUDA 12.0 使用cusparseSpSMGeneric API原生支持 int64CUDA 12.0 之前的分发逻辑回退到 int32-only 的csrsm2spsolve_triangular的分发逻辑在 cupyx/scipy/sparse/linalg/_solve.py 中有完整实现_should_use_spsm()判断非 ROCm 平台即 CUDA 12.0时优先走cusparseSpSM否则回退到csrsm2分支并在该分支调用cusparse._check_int32_indices(A, spsolve_triangular)主动拒绝 int64 索引。_check_int32_indices本身定义于 cupyx/cusparse.py是旧版 int32-only 入口csrgeam、csrgemm、csrsm2、csrlsvqr的统一校验点。注意即使数据本身放得下只要索引是 int64上述操作就会失败。规避方法是在调用前将索引显式转为 int32例如通过safely_cast_index_arrays确认安全后转换或改用迭代法如cg、gmres等不受该限制的求解器。与 SciPy 的相互转换需要显式转换且代价高昂CuPy 与 SciPy 的稀疏对象不能隐式互转SciPy 函数不能直接接收cupyx.scipy.sparse对象反之亦然。转换必须显式进行import cupy import cupyx.scipy.sparse as csp import scipy.sparse as sp # SciPy - CuPy把 SciPy 对象传给匹配的 CuPy 构造函数 A_scipy sp.csr_matrix([[1, 0], [0, 2]]) A_cupy csp.csr_array(A_scipy) # 或 csp.csr_matrix(A_scipy) # CuPy - SciPy调用 .get() 方法 B_scipy A_cupy.get() # array 实例返回 scipy *_arraymatrix 实例返回 scipy *_matrix转换规则的关键点SciPy → CuPy将 SciPy 稀疏数组/矩阵直接传给对应的 CuPy 构造函数如csr_array或csr_matrixCuPy → SciPy使用稀疏对象的.get()方法。稀疏array实例返回 SciPy 的*_array稀疏matrix实例返回 SciPy 的*_matrix。这一行为在源码中有清晰印证cupyx/scipy/sparse/_csr.py 的csr_base.get()实现会检查isinstance(self, _base.sparray)来决定构造scipy.sparse.csr_array还是scipy.sparse.csr_matrix。性能提醒CuPy 与 SciPy 之间的转换必然涉及主机与设备host-device之间的数据传输代价高昂应避免在性能敏感路径上频繁互转。与 CuPy 稠密 ndarray 的转换全程留在 GPU 上CuPy ndarray → 稀疏对象把稠密数组传给稀疏构造函数例如csp.csr_array(dense_cupy_ndarray)稀疏对象 → CuPy ndarray使用稀疏对象的toarray()方法。import cupy import cupyx.scipy.sparse as csp dense cupy.array([[1, 0], [0, 2]], dtypecupy.float32) sp csp.csr_array(dense) # 稠密 - 稀疏 back sp.toarray() # 稀疏 - 稠密返回 cupy.ndarraytoarray定义于基类 cupyx/scipy/sparse/_base.py内部委托给tocsr().toarray()各格式类如_coo.py、_csc.py也都有各自的toarray实现。关键优势CuPy ndarray 与 CuPy 稀疏对象之间的转换不会产生主机-设备数据传输数据始终驻留在 GPU 显存中因此这是处理 GPU 工作流时最推荐的稠密/稀疏互转方式。完整 API 导览稀疏数组类array推荐用于新代码coo_array、csc_array、csr_array、dia_array以及抽象基类sparray。稀疏矩阵类matrix用于兼容旧代码coo_matrix、csc_matrix、csr_matrix、dia_matrix以及抽象基类spmatrix。构建稀疏数组array 风格总是返回稀疏数组函数作用eye_array单位对角稀疏数组diags_array从对角线构造稀疏数组block_array由分块构造稀疏数组random_array随机稀疏数组构建稀疏矩阵matrix 风格向后兼容函数作用eye单位对角稀疏矩阵identity单位稀疏矩阵diags从对角线构造spdiags从对角线数组构造bmat从块矩阵构造rand/random随机稀疏矩阵组合与操作Combining and manipulating与 SciPy 一致组合操作会保留输入类型只要任一输入是稀疏数组结果就是稀疏数组否则结果为稀疏矩阵*_array构建函数则总是返回稀疏数组。需要注意matrix_transpose、permute_dims、swapaxes在 CuPy 中仅支持 2-D。kron/kronsumKronecker 积 / 积和hstack/vstack水平 / 垂直堆叠block_diag块对角tril/triu下三角 / 上三角提取matrix_transpose/permute_dims/swapaxes轴操作仅 2-D稀疏工具函数find找出非零元素返回非零值的坐标与数据get_index_dtype根据输入数组与maxval确定合适的索引 dtypeint32 或 int64safely_cast_index_arrays安全地将索引数组降级/转换为目标 dtype若维度放不下则抛出ValueError稀疏对象类型判定与 SciPy 的语义完全一致issparse同时接受稀疏数组与稀疏矩阵isspmatrix以及各格式判定isspmatrix_csc、isspmatrix_csr、isspmatrix_coo、isspmatrix_dia仅对稀疏矩阵返回True要判断某格式的稀疏数组请使用isinstance(x, csr_array)等isinstance检查。子模块cupyx.scipy.sparse.csgraph压缩稀疏图例程。当前 cupyx/scipy/sparse/csgraph/init.py 导出了connected_components连通分量。cupyx.scipy.sparse.linalg稀疏线性代数例程。根据 cupyx/scipy/sparse/linalg/init.py包含直接求解/分解spsolve、spsolve_triangular、splu、spilu、factorized、SuperLU迭代求解器cg、cgs、bicgstab、gmres、minres、lsqr、lsmr特征值/奇异值eigsh、svds、lobpcg辅助norm、matrix_power、LinearOperator、aslinearoperator异常scipy.sparse.SparseEfficiencyWarning格式转换等低效操作时发出警告如_solve.py中spsolve遇到非 CSR 输入时提示 CSR format is required. Converting to CSR format.scipy.sparse.SparseWarning稀疏警告基类两者从 cupyx/scipy/sparse/_base.py 导出见 cupyx/scipy/sparse/init.py。实战示例GPU 上的稀疏线性系统求解下面组合上述知识演示一个完整的 GPU 稀疏工作流构造稀疏矩阵、转换为最优格式、调用spsolve求解并验证 dtype 约束。import cupy import cupyx.scipy.sparse as csp from cupyx.scipy.sparse.linalg import spsolve # 1. 从稠密数组构造 CSR 稀疏数组数据留在 GPU 上无主机-设备传输 dense cupy.array([ [4.0, 1.0, 0.0, 0.0], [1.0, 4.0, 1.0, 0.0], [0.0, 1.0, 4.0, 1.0], [0.0, 0.0, 1.0, 4.0], ], dtypecupy.float32) A csp.csr_array(dense) print(format:, A.format, | data dtype:, A.data.dtype, | index dtype:, A.indices.dtype) b cupy.ones(4, dtypecupy.float32) # 2. 稀疏求解内部要求 CSR 格式 int32 索引 x spsolve(A.tocsr(), b) print(solution:, x) # 3. 索引 dtype 自动选择验证小矩阵应为 int32 assert A.indices.dtype cupy.int32 assert A.indptr.dtype cupy.int32 # 4. 与 SciPy 互转涉及主机-设备传输应尽量少用 A_host A.get() # 返回 scipy.sparse.csr_array A_back csp.csr_array(A_host) # 再转回 CuPy # 5. 稀疏 - 稠密仍在 GPU 上 dense_again A.toarray() assert isinstance(dense_again, cupy.ndarray)总结cupyx.scipy.sparse为 GPU 上的稀疏数值计算提供了与 SciPy 高度一致的接口核心要点可归纳为格式与 dtype 受限仅支持 COO/CSR/CSC/DIA 四种格式数据 dtype 仅限bool、float32、float64、complex64、complex128索引 dtype 由get_index_dtype在 int32/int64 间自动选择int64 有已知限制spsolve、spilu以及 CUDA 12.0 之前的spsolve_triangular仅支持 int32 索引会抛出ValueError转换路径分明与 SciPy 互转必须显式进行且伴随主机-设备传输与 CuPy ndarray 互转全程留在 GPU成本低优先使用 array 类新代码应选用*_array系列遵循 NumPy 的*逐元素 /矩阵乘语义为未来 SciPy 弃用*_matrix做准备。理解这些差异与限制能够让你在 GPU 稀疏工作流中避开常见的 dtype 陷阱写出既正确又高效的代码。【免费下载链接】cupyNumPy SciPy for GPU项目地址: https://gitcode.com/GitHub_Trending/cu/cupy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考