torch.cat/torch.stack 拼接稀疏张量会隐式稠密化,效率低下;应使用 torch_sparse.cat()、手动拼接 indices/values 或转为 SparseTensor 后拼接,并注意 COO 排序、设备统一及版本兼容性。

torch.sparse 本身不提供高效拼接或原地操作,直接用 torch.cat 或 torch.stack 拼接稀疏张量会触发隐式稠密化,这是效率低下的根本原因。
拼接前先检查 storage 格式是否一致
SparseTensor 和 torch.sparse.Tensor 的底层存储机制不同,混用会导致额外转换开销:
- torch.sparse.FloatTensor 只支持 COO 格式,且不支持自动合并重复索引
- torch_sparse.SparseTensor 支持 COO/CSR/CSC,并内置 coalesce()、to_symmetric() 等优化方法
- torch_geometric.utils.to_torch_coo_tensor() 返回的是标准 PyTorch 稀疏张量,但丢失了 torch_sparse 的元信息
常见错误现象:拼接后调用 torch.sparse.mm() 报错 RuntimeError: Expected sparse tensor input,其实是输入已悄悄转成 dense。
避免隐式稠密化的三种拼接方式
- 用torch_sparse.cat()(推荐):专为 SparseTensor 设计,支持沿 dim=0 或 dim=1 拼接,不触发稠密化
- 手动拼接 indices 和 values:适用于 torch.sparse.Tensor,需手动偏移行列索引并更新 size
- 转成 SparseTensor 再拼:调用 SparseTensor.from_edge_index() 构建,再用 .cat(),兼容性最好
示例(手动拼接 COO):
import torch from torch_sparse import SparseTensor <h1>两个 3x4 和 2x4 的稀疏张量</h1><p>idx1 = torch.tensor([[0,1], [2,0]]) val1 = torch.tensor([1.0, 2.0]) idx2 = torch.tensor([[0,1], [1,3]]) val2 = torch.tensor([3.0, 4.0])</p><h1>拼接:第二维相同,沿 dim=0 拼 → 结果应为 5x4</h1><p>idx2_shifted = idx2.clone() idx2_shifted[0] += 3 # 行索引 +3 idx_cat = torch.cat([idx1, idx2_shifted], dim=1) val_cat = torch.cat([val1, val2]) sparse_cat = torch.sparse_coo_tensor(idx_cat, val_cat, size=(5, 4)).coalesce()</p>
GPU 上拼接失败的典型原因
-torch.sparse 的 COO 拼接在 CUDA 上不支持 coalesce() 自动调用,必须显式执行
- torch_sparse.SparseTensor 的 .cat() 默认在 CPU 上运行,跨设备拼接需提前统一 device
- 某些旧版 torch-sparse(如 0.6.9)对 CUDA 12.6+ 支持不完整,报错 Not implemented for 'SparseCUDA'参数差异关键点:
立即学习“Python免费学习笔记(深入)”;
-
torch.cat([a, b], dim=0)对稀疏张量无效 —— 它只处理 dense 张量 -
SparseTensor.cat([a, b], dim=0)是唯一安全的拼接入口 -
torch.sparse.sum()或torch.sparse.mean()不可用于拼接,它们是归约操作
内存暴涨往往发生在 coalesce 阶段
coalesce() 会重排索引并聚合重复位置的值,但若输入索引未排序,它可能分配临时 buffer 导致峰值内存翻倍。尤其当边数超百万时:
- 先用 torch.argsort() 对 indices[0] 排序再传入 coalesce()
- 或改用 SparseTensor.from_edge_index(edge_index, edge_attr, is_sorted=True) 避免重复排序
- 分块拼接:每 10 万条边做一次 cat + coalesce,再整体合并,比一次性处理更稳
容易被忽略的一点:PyTorch 2.0+ 中 torch.sparse 的 API 仍处于 experimental 状态,所有拼接行为都不保证向后兼容;生产环境建议锁定 torch-sparse==0.6.17 并全程使用 SparseTensor 接口,而不是混用原生稀疏张量。


















