Important
paddle_scatter 是基于 Paddle 后端 所开发的稀疏计算 API 拓展仓库,包括 scatter,segment,gather 三大类稀疏计算 API。仓库原型参照:pytorch_scatter。拓展仓库中的稀疏计算 API 通过 Paddle 原生 python API 以及自定义 C++ 算子实现。
推荐在运行前安装 Paddle 3.0 或 develop 版本。
运行正确性在 Ubuntu 20.04.6 环境下经过验证。
- Paddle 3.0
cpu 版本或 gpu 版本均可
- Package Build
cd paddle_scatter
pip install -v .- Simple Example
pip install pytest
cd paddle_scatter/paddle_scatter
pytest -v ./testsimport paddle
from paddle_scatter import scatter_max
src = paddle.to_tensor([[2, 0, 1, 4, 3], [0, 2, 1, 3, 4]])
index = paddle.to_tensor([[4, 5, 4, 2, 3], [0, 0, 2, 2, 1]])
out, argmax = scatter_max(src, index, dim=-1)
print(out)
Tensor(shape=[2, 6], dtype=int64, place=Place(gpu:0), stop_gradient=True,
[[0, 0, 4, 3, 2, 0],
[2, 4, 3, 0, 0, 0]])
print(argmax)
Tensor(shape=[2, 6], dtype=int64, place=Place(gpu:0), stop_gradient=True,
[[5, 5, 3, 4, 0, 1],
[1, 4, 3, 5, 5, 5]])-
一级 API: scatter,segment_coo,segment_csr,gather_coo,gather_csr
-
二级 API: scatter_add,scatter_mean,scatter_mul,scatter_min,scatter_max; segment_sum_coo, segment_add_coo, segment_mean_coo, segment_min_coo, segment_max_coo; segment_sum_csr, segment_add_csr, segment_mean_csr, segment_min_csr, segment_max_csr
-
组合 API: scatter_softmax,scatter_log_softmax,scatter_logsumexp
-
Paddle 自定义 C++ 算子以及扩展技术说明: 自定义 C++ 算子:https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/custom_op/new_cpp_op_cn.html 自定义 C++ 扩展:https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/custom_op/cpp_extension_cn.html
scatter(src: paddle.Tensor, index: paddle.Tensor, dim: int = -1, out: Optional[paddle.Tensor] = None, dim_size: Optional[int] = None, reduce: Optional[str] = "sum")
分散计算,将 src 按照指定的 index 延 dim 轴进行 reduce 规约合并。若指定 out 则输出到 out,若指定 dim_size 则规约后输出的 dim 维的维数是 dim_size。
符号表示:
-
src形状:$(x_{0}, ..., x_{i-1}, x_{i}, x_{i+1}, ..., x_{n-1})$ 其中$i$ =dim -
index形状:$(x_0, ..., x_{i-1}, x_i, x_{i+1}, ..., x_{n-1})$ 其中$i$ =dim -
out形状:$(x_0, ..., x_{i-1}, y, x_{i+1}, ..., x_{n-1})$ -
index的值必须属于$[0, 1, ..., y-1]$ ,且值的顺序大小没有限制
此 API 对 index 支持广播,所以 index 的形状还可以是:
以一维情况下 reduce = "sum" 为例,数学计算公式为:
参数:
- src (paddle.Tensor) - 源 tensor。
- index (paddle.Tensor) - 用于分散计算的指定下标,形状请参考上述文档。
- dim (int) - 分散计算的目标维度。默认值为 -1。
- out (paddle.Tensor,可选) - 输出 tensor。默认值为 None。
- dim_size (int,可选) - 若未指定
out,输出 tensor 在dim维的维数将被设为dim_size;若未指定dim_size,输出 tensor 在dim维的维数将被自动设为index.max() + 1。默认值为 None。 - reduce (str,可选) - 规约类型,支持 "sum","add","mul","mean","min","max"。默认值为 "sum"。
返回: 分散规约计算后的 tensor。
代码示例:
from paddle_scatter import scatter
src = paddle.randn([10, 6, 64])
index = paddle.tensor([0, 1, 0, 1, 2, 1])
# Broadcasting in the first and last dim
out = scatter(src, index, dim=1, reduce="sum")
print(out.shape)
[10, 3, 64]
# Specify `dim_size`
out = scatter(src, index, dim=1, dim_size=4, reduce="sum")
print(out.shape)
[10, 4, 64]
# Specify `out`
out = paddle.empty([10, 3, 64])
scatter(src, index, dim=1, out=out, reduce="sum")
print(out.shape)
[10, 3, 64]segment_coo(src: paddle.Tensor, index: paddle.Tensor, out: Optional[paddle.Tensor] = None, dim_size: Optional[int] = None, reduce: Optional[str] = "sum")
以 coordinate 的稀疏格式分段计算,将 src 沿 index 最后一维,按照 index 的值分组进行 reduce 规约合并。若指定 out 则输出到 out,若指定 dim_size 则规约后输出的 dim 维的维数是 dim_size。
符号表示:
-
src形状:$(x_1, ..., x_{m-1}, x_m, x_{m+1}, ..., x_n)$ -
index形状:$(x_1, ..., x_{m-1}, x_m)$ -
out形状:$(x_1, ..., x_{m-1}, y, x_{m+1}, ..., x_n)$ -
index的值必须属于$[0, 1, ..., y-1]$ ,且值的顺序必须是升序
此 API 对 index 支持广播,所以 index 的形状还可以是:
以一维情况下 reduce = "sum" 为例,数学计算公式为:
参数:
- src (paddle.Tensor) - 源 tensor。
- index (paddle.Tensor) - 用于分段计算的指定下标,形状请参考上述文档。
- out (paddle.Tensor,可选) - 输出 tensor。默认值为 None。
- dim_size (int,可选) - 若未指定
out,输出 tensor 在dim维的维数将被设为dim_size;若未指定dim_size,输出 tensor 在dim维的维数将被自动设为index.max() + 1。默认值为 None。 - reduce (str,可选) - 规约类型,支持 "sum","add","mean","min","max"。默认值为 "sum"。
返回: 以 coordinate 的稀疏格式分段规约计算后的 tensor。
代码示例:
from paddle_scatter import segment_coo
src = paddle.randn([10, 6, 64])
index = paddle.to_tensor([0, 0, 1, 1, 1, 2])
index = index.view(1, -1) # Broadcasting in the first and last dim.
out = segment_coo(src, index, reduce="sum")
print(out.shape)
[10, 3, 64]segment_csr(src: paddle.Tensor, indptr: paddle.Tensor, out: Optional[paddle.Tensor] = None, reduce: Optional[str] = "sum")
以 compressed sparse row 的稀疏格式分段计算,将 src 沿 indptr 最后一维,按照 indptr 指定的下标范围进行分段 reduce 规约合并。若指定 out 则输出到 out。
符号表示:
-
src形状:$(x_1, ..., x_{m-1}, x_m, x_{m+1}, ..., x_n)$ -
indptr形状:$(x_1, ..., x_{m-1}, y)$ ,其中$y$ 的大小无限制 -
out形状:$(x_1, ..., x_{m-1}, y - 1, x_{m+1}, ..., x_n)$ -
indptr的值必须属于$[0, 1, ..., x_m]$ ,且值的顺序必须是升序
此 API 对 indptr 支持广播,所以 indptr 的形状还可以是:
以一维情况下 reduce = "sum" 为例,数学计算公式为:
参数:
- src (paddle.Tensor) - 源 tensor。
- indptr (paddle.Tensor) - 用于分段计算的下标指针,形状请参考上述文档。
- out (paddle.Tensor,可选) - 输出 tensor。默认值为 None。
- reduce (str,可选) - 规约类型,支持 "sum","add","mean","min","max"。默认值为 "sum"。
返回: 以 compressed sparse row 的稀疏格式分段规约计算后的 tensor。
代码示例:
from paddle_scatter import segment_csr
src = paddle.randn([10, 6, 64])
indptr = paddle.tensor([0, 2, 5, 6])
indptr = indptr.view(1, -1) # Broadcasting in the first and last dim.
out = segment_csr(src, indptr, reduce="sum")
print(out.shape)
[10, 3, 64]gather_coo(src: paddle.Tensor, index: paddle.Tensor, out: Optional[paddle.Tensor] = None)
以 coordinate 的稀疏格式,沿着 index 最后一维,从 src 中按照 index 的下标值取出对应元素。若指定 out 则输出到 out。
符号表示:
-
src形状:$(x_1, ..., x_{m-1}, x_m, x_{m+1}, ..., x_n)$ -
index形状:$(x_1, ..., x_{m-1}, y)$ ,其中$y$ 的大小无限制 -
out形状:$(x_1, ..., x_{m-1}, y, x_{m+1}, ..., x_n)$ -
index的值必须属于$[0, 1, ..., x_m - 1]$ ,且值的顺序必须是升序
此 API 对 index 支持广播,所以 index 的形状还可以是:
以一维情况为例,数学计算公式为:
参数:
- src (paddle.Tensor) - 源 tensor。
- index (paddle.Tensor) - 稀疏取出操作的指定下标,形状请参考上述文档。
- out (paddle.Tensor,可选) - 输出 tensor。默认值为 None。
返回: 以 coordinate 的稀疏格式取出的 tensor。
代码示例:
from paddle_scatter import gather_coo
src = paddle.to_tensor([1, 2, 3, 4])
index = paddle.to_tensor([0, 0, 1, 1, 1, 3])
out = gather_coo(src, index)
print(out)
Tensor(shape=[6], dtype=int64, place=Place(cpu), stop_gradient=True,
[1, 1, 2, 2, 2, 4])gather_csr(src: paddle.Tensor, indptr: paddle.Tensor, out: Optional[paddle.Tensor] = None)
以 compressed sparse row 的稀疏格式,沿 indptr 最后一维,按照 indptr 指定的下标范围从 src 中取出对应元素。若指定 out 则输出到 out。
符号表示:
-
src形状:$(x_1, ..., x_{m-1}, x_m, x_{m+1}, ..., x_n)$ -
indptr形状:$(x_1, ..., x_{m-1}, y)$ ,其中需满足$y = x_m + 1$ -
out形状:$(x_1, ..., x_{m-1}, k, x_{m+1}, ..., x_n)$ ,其中$k$ 指indptr所指示的下标分段数 -
indptr的值必须属于$[0, 1, ..., x_m]$ ,且值的顺序必须是升序
此 API 对 indptr 支持广播,所以 indptr 的形状还可以是:
以一维情况为例,数学计算公式为:
参数:
- src (paddle.Tensor) - 源 tensor。
- indptr (paddle.Tensor) - 稀疏取出操作的下标指针,形状请参考上述文档。
- out (paddle.Tensor,可选) - 输出 tensor。默认值为 None。
返回: 以 compressed sparse row 的稀疏格式取出的 tensor。
代码示例:
from paddle_scatter import gather_csr
src = paddle.to_tensor([1, 2, 3, 4])
indptr = paddle.to_tensor([0, 2, 5, 5, 6])
out = gather_csr(src, indptr)
print(out)
Tensor(shape=[6], dtype=int64, place=Place(cpu), stop_gradient=True,
[1, 1, 2, 2, 2, 4])