diff --git a/rfcs/APIs/20230405_api_design_for_sparse_any.md b/rfcs/APIs/20230405_api_design_for_sparse_any.md
new file mode 100644
index 000000000..1fa41216a
--- /dev/null
+++ b/rfcs/APIs/20230405_api_design_for_sparse_any.md
@@ -0,0 +1,436 @@
+# paddle.sparse.any 设计文档
+
+| API名称 | paddle.sparse.any |
+|------------------------------------------------------------|---------------------------------------------|
+| 提交作者 | zrr1999 |
+| 提交时间 | 2023-04-05 |
+| 版本号 | V1.0 |
+| 依赖飞桨版本 | develop |
+| 文件名 | 20230405_api_design_for_sparse_any.md
|
+
+# 一、概述
+## 1、相关背景
+为了提升飞桨 API 丰富度,针对 Paddle 的两种稀疏 Tensor 格式 COO 与 CSR ,都需新增 any 的计算逻辑,
+any 的计算逻辑是元素中任意一个为真结果即为真。
+一共需要新增 2 个 kernel 的前向,其中 COO 格式的 axis 支持任意维度,CSR 格式的 axis 可只支持-1,即按行读取。
+另外当 axis=None 时所有元素进行 any 运算。
+
+## 3、意义
+支持稀疏 tensor 的 any 操作,丰富基础功能,提升稀疏 tensor 的 API 完整度。
+
+# 二、飞桨现状
+目前paddle缺少相关功能实现。
+
+# 三、业内方案调研
+## Pytorch
+Pytorch 中相关实现如下(pytorch/aten/src/ATen/native/ReduceOps.cpp),
+PyTorch 只支持COO格式的稀疏张量,且与普通张量的实现放在了一起。
+
+```cpp
+template
+inline void allany_impl(
+ const Tensor& self,
+ const Tensor& result,
+ IntArrayRef dims,
+ bool keepdim,
+ Stub& stub) {
+ if (self.numel() == 0) {
+ result.fill_(identity);
+ } else if (self.numel() == 1) {
+ result.copy_(self.view_as(result).to(at::kBool));
+ } else {
+ auto iter = get_allany_iter(self, result, dims, keepdim);
+ stub(iter.device_type(), iter);
+ }
+}
+
+TORCH_IMPL_FUNC(all_out)
+(const Tensor& self, int64_t dim, bool keepdim, const Tensor& result) {
+ allany_impl<1>(self, result, dim, keepdim, and_stub);
+}
+
+TORCH_IMPL_FUNC(all_all_out)(const Tensor& self, const Tensor& result) {
+ allany_impl<1>(self, result, {}, false, and_stub);
+}
+
+TORCH_IMPL_FUNC(any_out)
+(const Tensor& self, int64_t dim, bool keepdim, const Tensor& result) {
+ allany_impl<0>(self, result, dim, keepdim, or_stub);
+}
+```
+
+## scipy
+scipy.sparse库中没有any()函数。但是,可以使用numpy库中的any()函数在稀疏矩阵中执行相同的操作。
+
+## paddle DenseTensor
+DenseTensor中的any被定义为paddle.any(x, axis=None, dtype=None, keepdim=False, name=None),
+在指定维度上进行进行逻辑或运算的 Tensor,数据类型和输入数据类型一致。
+代码如下
+```python
+import paddle
+
+x = paddle.to_tensor([[1, 0], [1, 1]], dtype='int32')
+x = paddle.assign(x)
+print(x)
+x = paddle.cast(x, 'bool')
+# x is a bool Tensor with following elements:
+# [[True, False]
+# [True, True]]
+
+# out1 should be [True]
+out1 = paddle.any(x) # [True]
+print(out1)
+
+# out2 should be [True, True]
+out2 = paddle.any(x, axis=0) # [True, True]
+print(out2)
+
+# keepdim=False, out3 should be [True, True], out.shape should be (2,)
+out3 = paddle.any(x, axis=-1) # [True, True]
+print(out3)
+
+# keepdim=True, result should be [[True], [True]], out.shape should be (2,1)
+out4 = paddle.any(x, axis=1, keepdim=True) # [[True], [True]]
+print(out4)
+```
+
+但是此处是Dense的,直接使用指针在Sparse中不可行。
+
+# 四、对比分析
+
+为了适配paddle phi库的设计模式,需自行设计实现方式
+
+# 五、方案设计
+
+## 命名与参数设计
+
+在 paddle/phi/kernels/sparse/unary_kernel.h 中, kernel设计为
+
+```cpp
+
+template
+void AnyCooKernel(const Context& dev_ctx,
+ const SparseCooTensor& x,
+ const IntArray& axis,
+ DataType dtype,
+ bool keep_dim,
+ SparseCooTensor* out);
+
+template
+void AnyCsrKernel(const Context& dev_ctx,
+ const SparseCsrTensor& x,
+ const IntArray& axis,
+ DataType dtype,
+ bool keep_dim,
+ SparseCsrTensor* out);
+
+```
+
+在 paddle/phi/kernels/sparse/unary_grad_kernel.h 中, kernel设计为
+
+```cpp
+template
+void AnyCooGradKernel(const Context& dev_ctx,
+ const SparseCooTensor& x,
+ const SparseCooTensor& dout,
+ const IntArray& axis,
+ bool keep_dim,
+ SparseCooTensor* dx);
+
+template
+void AnyCsrGradKernel(const Context& dev_ctx,
+ const SparseCsrTensor& x,
+ const SparseCsrTensor& dout,
+ const IntArray& axis,
+ bool keep_dim,
+ SparseCsrTensor* dx);
+```
+
+并在yaml中新增对应API
+
+sparse_ops.yaml
+```yaml
+- op : any
+ args : (Tensor x, IntArray axis={}, bool keepdim=false)
+ output : Tensor(out)
+ infer_meta :
+ func : AnyInferMeta
+ kernel :
+ func : any_coo{sparse_coo -> sparse_coo},
+ any_csr{sparse_csr -> sparse_csr}
+ data_type : x
+ backward : any_grad
+
+```
+
+sparse_backward_ops.yaml
+```yaml
+- backward_op : any_grad
+ forward : any(Tensor x, IntArray axis={}, bool keepdim=false) -> Tensor(out)
+ args : (Tensor x, Tensor out_grad, IntArray axis={}, bool keepdim=false)
+ output : Tensor(x_grad)
+ infer_meta :
+ func : UnchangedInferMeta
+ param : [x]
+ kernel :
+ func : any_coo_grad {sparse_coo -> sparse_coo},
+ any_csr_grad {sparse_csr -> sparse_csr}
+
+```
+
+相应的InferMeta函数可以复用稠密矩阵的函数。
+
+## 底层OP设计
+对于axis=None的简单情况,只需要把value值进行逻辑或运算,并对相应的位置参数进行修改即可。
+
+对于COO格式的其他情况,主要分为两步,
+第一步构建索引(排除掉axis维度)到序号的映射,
+得到的结果按序号顺序作为输出结果的索引即可。
+
+对于CSR格式,由于只需要考虑axis=-1的情况,因此对于2维情况,
+只需要out_cols全部置零,相邻x_crows有变化的分别改为变化量为1,
+无变化保持无变化,而value是相应的逻辑或运算,大致逻辑代码如下
+```cpp
+void AnyCsrKernel(const Context& dev_ctx,
+ const SparseCsrTensor& x,
+ const IntArray& axis,
+ bool keep_dim,
+ SparseCsrTensor* out) {
+ size_t n_dim = axis.size();
+ const DenseTensor& x_crows = x.crows();
+ const DenseTensor& x_values = x.values();
+ const auto* x_crows_data = x_crows.data();
+ const T* x_values_data = x_values.data();
+
+ DenseTensor out_crows, out_cols, out_values;
+ DDim out_dims;
+ if (n_dim == 0) {
+ out_dims = make_ddim({1, 1});
+ out_crows = Empty(dev_ctx, {2}); // crows = [0, 1]
+ auto* out_crows_data = out_crows.data();
+ out_crows_data[0] = 0;
+ out_crows_data[0] = 1;
+
+ out_cols = Empty(dev_ctx, {1}); // crows = [0]
+ auto* out_cols_data = out_cols.data();
+ out_cols_data[0] = 0;
+
+ out_values = phi::Any(dev_ctx, x.values(), {}, true);
+ } else {
+ PADDLE_ENFORCE_EQ(axis[0],
+ -1,
+ phi::errors::Unimplemented(
+ "`axis` of AnyCsrKernel only support None or -1 now."
+ "More number will be supported in the future."));
+ out_dims = make_ddim({x.dims()[0], 1});
+ out_crows = EmptyLike(dev_ctx, x.crows());
+ auto* out_crows_data = out_crows.data();
+ out_crows_data[0] = 0;
+
+ std::vector out_data;
+ for (int i = 0; i < x.dims()[0]; ++i) {
+ if (x_crows_data[i] != x_crows_data[i + 1]) {
+ bool any_value = False;
+ for (auto j = x_crows_data[i]; j < x_crows_data[i + 1]; ++j) {
+ any_value ||= x_values_data[j];
+ }
+ out_crows_data[i + 1] = out_crows_data[i] + 1;
+ out_data.push_back(any_value);
+ } else {
+ out_crows_data[i + 1] = out_crows_data[i];
+ }
+ }
+
+ out_cols =
+ Empty(dev_ctx, {static_cast(out_data.size())});
+ out_values =
+ Empty(dev_ctx, {static_cast(out_data.size())});
+ auto* out_cols_data = out_cols.data();
+ T* out_values_data = out_values.data();
+ for (size_t i = 0; i < out_data.size(); ++i) {
+ out_cols_data[i] = 0;
+ out_values_data[i] = out_data[i];
+ }
+ }
+ out->SetMember(out_crows, out_cols, out_values, out_dims);
+}
+```
+对于3维情况,按层考虑即可。
+
+对于反向传播,dx的coo和csr的索引(indices、crows、cols)均与x保持不变,
+value则取决于dout的相应位置值。
+
+## API实现方案
+
+对于SparseCsrTensor和SparseCooTensor有相同的API,
+
+均只需要给定输入张量和维度转换目标。
+
+具体的API为`paddle.sparse.any(x, axis=None, keepdim=False)`
+
+- x: 输入张量
+- axis: 进行逻辑或运算的维度,例如-1表示最后一个维度进行逻辑或运算。
+- keepdim: 是否保持输入和输出维度不变,
+例如$[5, 5]$的张量输入对第一个维度进行逻辑或运算,若保持维度不变则输出为$[1, 5]$,否则为$[5]$。
+
+# 六、测试和验收的考量
+
+测试考虑的case如下:
+
+- 正确性
+- csr对2维和3维不同`axis`参数测试
+- coo对1维、2维、3维、6维和10维不同`axis`参数测试
+- 分别对每个测试样本分成keepdim为真或假
+
+具体样例如下
+
+```python
+class TestAny(unittest.TestCase):
+ # x: sparse, out: sparse
+ def check_result(self, x_shape, dims, keepdim, format):
+ mask = paddle.randint(0, 2, x_shape).astype("float32")
+ # "+ 1" to make sure that all zero elements in "origin_x" is caused by multiplying by "mask",
+ # or the backward checks may fail.
+ origin_x = (paddle.rand(x_shape, dtype='float32') + 1) * mask
+ dense_x = origin_x.detach()
+ dense_x.stop_gradient = False
+ dense_out = paddle.any(dense_x, dims, keepdim=keepdim)
+ if format == "coo":
+ sp_x = origin_x.detach().to_sparse_coo(len(x_shape))
+ else:
+ sp_x = origin_x.detach().to_sparse_csr()
+ sp_x.stop_gradient = False
+ sp_out = paddle.sparse.any(sp_x, dims, keepdim=keepdim)
+
+ np.testing.assert_allclose(
+ sp_out.to_dense().numpy(), dense_out.numpy(), rtol=1e-05
+ )
+ dense_out.backward()
+ sp_out.backward()
+ np.testing.assert_allclose(
+ sp_x.grad.to_dense().numpy(),
+ (dense_x.grad * mask).numpy(),
+ rtol=1e-05,
+ )
+
+ def test_any_1d(self):
+ self.check_result([5], None, False, 'coo')
+ self.check_result([5], None, True, 'coo')
+ self.check_result([5], 0, True, 'coo')
+ self.check_result([5], 0, False, 'coo')
+
+ def test_any_2d(self):
+ self.check_result([2, 5], None, False, 'coo')
+ self.check_result([2, 5], None, True, 'coo')
+ self.check_result([2, 5], 0, True, 'coo')
+ self.check_result([2, 5], 0, False, 'coo')
+ self.check_result([2, 5], 1, False, 'coo')
+ self.check_result([2, 5], None, True, 'csr')
+ self.check_result([2, 5], -1, True, 'csr')
+
+ def test_any_3d(self):
+ self.check_result([6, 2, 3], -1, True, 'csr')
+ for i in [0, 1, -2, None]:
+ self.check_result([6, 2, 3], i, False, 'coo')
+ self.check_result([6, 2, 3], i, True, 'coo')
+
+ def test_any_nd(self):
+ for i in range(6):
+ self.check_result([8, 3, 4, 4, 5, 3], i, False, 'coo')
+ self.check_result([8, 3, 4, 4, 5, 3], i, True, 'coo')
+ # Randint now only supports access to dimension 0 to 9.
+ self.check_result([2, 3, 4, 2, 3, 4, 2, 3, 4], i, False, 'coo')
+
+class TestSparseAnyStatic(unittest.TestCase):
+ def check_result_coo(self, x_shape, dims, keepdim):
+ mask = paddle.randint(0, 2, x_shape)
+ origin_data = (paddle.rand(x_shape, dtype='float32') + 1) * mask
+ sparse_data = origin_data.detach().to_sparse_coo(
+ sparse_dim=len(x_shape)
+ )
+ indices_data = sparse_data.indices()
+ values_data = sparse_data.values()
+
+ dense_x = origin_data
+ dense_out = paddle.any(dense_x, dims, keepdim=keepdim)
+
+ paddle.enable_static()
+ with paddle.static.program_guard(
+ paddle.static.Program(), paddle.static.Program()
+ ):
+ indices = paddle.static.data(
+ name='indices',
+ shape=indices_data.shape,
+ dtype=indices_data.dtype,
+ )
+ values = paddle.static.data(
+ name='values', shape=values_data.shape, dtype=values_data.dtype
+ )
+ sp_x = paddle.sparse.sparse_coo_tensor(
+ indices,
+ values,
+ shape=origin_data.shape,
+ dtype=origin_data.dtype,
+ )
+ sp_out = paddle.sparse.any(sp_x, dims, keepdim=keepdim)
+ sp_dense_out = sp_out.to_dense()
+
+ sparse_exe = paddle.static.Executor()
+ sparse_fetch = sparse_exe.run(
+ feed={
+ 'indices': indices_data.numpy(),
+ "values": values_data.numpy(),
+ },
+ fetch_list=[sp_dense_out],
+ return_numpy=True,
+ )
+
+ np.testing.assert_allclose(
+ dense_out.numpy(), sparse_fetch[0], rtol=1e-5
+ )
+ paddle.disable_static()
+
+ def test_any_1d(self):
+ self.check_result_coo([5], None, False)
+ self.check_result_coo([5], None, True)
+ self.check_result_coo([5], 0, True)
+ self.check_result_coo([5], 0, False)
+
+ self.check_result_coo([2, 5], None, False)
+ self.check_result_coo([2, 5], None, True)
+ self.check_result_coo([2, 5], 1, True)
+ self.check_result_coo([2, 5], 0, True)
+ self.check_result_coo([2, 5], 1, False)
+ self.check_result_coo([2, 5], 0, False)
+
+ for i in [0, 1, -2, None]:
+ self.check_result_coo([6, 2, 3], i, False)
+ self.check_result_coo([6, 2, 3], i, True)
+
+ for i in range(6):
+ self.check_result_coo([8, 3, 4, 4, 5, 3], i, False)
+ self.check_result_coo([8, 3, 4, 4, 5, 3], i, True)
+ # Randint now only supports access to dimension 0 to 9.
+ self.check_result_coo([2, 3, 4, 2, 3, 4, 2, 3, 4], i, False)
+```
+
+
+# 七、可行性分析及规划排期
+
+方案主要自行实现核心算法
+预计5.10号前完成cpu部分的实现和测试
+预计5.10号前完成gpu部分的实现和测试
+预计5.15号前完成各种参数的实现和测试
+预计5.20号前完成文档
+
+# 八、影响面
+
+为独立新增op,对其他模块没有影响
+
+# 名词解释
+
+无
+
+# 附件及参考资料
+
+无
\ No newline at end of file