|
| 1 | +# paddle.Tensor.bucketize 设计文档 |
| 2 | + |
| 3 | +|API名称 | paddle.bucketize | |
| 4 | +|---|---| |
| 5 | +|提交作者<input type="checkbox" class="rowselector hidden"> | 李芳钰 | |
| 6 | +|提交时间<input type="checkbox" class="rowselector hidden"> | 2022-07-8 | |
| 7 | +|版本号 | V1.0 | |
| 8 | +|依赖飞桨版本<input type="checkbox" class="rowselector hidden"> | develop | |
| 9 | +|文件名 | 20220708_api_design_for_bucketize.md<br> | |
| 10 | + |
| 11 | +# 一、概述 |
| 12 | + |
| 13 | +## 1、相关背景 |
| 14 | +为了提升飞桨API丰富度,Paddle需要扩充API`paddle.bucketize`的功能。 |
| 15 | +## 2、功能目标 |
| 16 | +增加API`paddle.bucketize`,实现根据边界返回输入值的桶索引。 |
| 17 | +## 3、意义 |
| 18 | +飞桨支持`paddle.bucketize`的API功能。 |
| 19 | + |
| 20 | +# 二、飞桨现状 |
| 21 | +目前paddle可直接由`paddle.searchsorted`API,直接实现该功能。 |
| 22 | + |
| 23 | +paddle已经实现了[paddle.searchsorted](https://github.com/PaddlePaddle/Paddle/blob/release/2.3/python/paddle/tensor/search.py#L910)API,所以只需要调用该API既可以实现该功能。 |
| 24 | + |
| 25 | +需要注意的是`paddle.bucketize`处理的sorted_sequence特殊要求为1-D Tensor。 |
| 26 | + |
| 27 | +# 三、业内方案调研 |
| 28 | +## Numpy |
| 29 | +### 实现方法 |
| 30 | +以现有numpy python API组合实现,[代码位置](https://github.com/numpy/numpy/blob/v1.23.0/numpy/lib/function_base.py#L5447-L5555). |
| 31 | +其中核心代码为: |
| 32 | +```Python |
| 33 | + x = _nx.asarray(x) |
| 34 | + bins = _nx.asarray(bins) |
| 35 | + |
| 36 | + # here for compatibility, searchsorted below is happy to take this |
| 37 | + if np.issubdtype(x.dtype, _nx.complexfloating): |
| 38 | + raise TypeError("x may not be complex") |
| 39 | + |
| 40 | + mono = _monotonicity(bins) |
| 41 | + if mono == 0: |
| 42 | + raise ValueError("bins must be monotonically increasing or decreasing") |
| 43 | + |
| 44 | + # this is backwards because the arguments below are swapped |
| 45 | + side = 'left' if right else 'right' |
| 46 | + if mono == -1: |
| 47 | + # reverse the bins, and invert the results |
| 48 | + return len(bins) - _nx.searchsorted(bins[::-1], x, side=side) |
| 49 | + else: |
| 50 | + return _nx.searchsorted(bins, x, side=side) |
| 51 | +``` |
| 52 | +整体逻辑为: |
| 53 | + |
| 54 | +- 通过`_monotonicity`判断箱子是否单调递增或者递减。 |
| 55 | +- 然后根据`mono`和参数`right`决定是否需要反转箱子。 |
| 56 | +- 最后也是通过`searchsorted`直接返回输入对应的箱子索引。 |
| 57 | + |
| 58 | +## Pytorch |
| 59 | +Pytorch中有API`torch.bucketize(input, boundaries, *, out_int32=False, right=False, out=None) → Tensor`。在pytorch中,介绍为: |
| 60 | +``` |
| 61 | +Returns the indices of the buckets to which each value in the input belongs, where the boundaries of the buckets are set by boundaries. Return a new tensor with the same size as input. If right is False (default), then the left boundary is closed. |
| 62 | +``` |
| 63 | + |
| 64 | +### 实现方法 |
| 65 | +在实现方法上,Pytorch的整体逻辑与Numpy基本一致,[代码位置](https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/native/Bucketization.cpp)。其中核心代码为: |
| 66 | +```c++ |
| 67 | +Tensor& bucketize_out_cpu(const Tensor& self, const Tensor& boundaries, bool out_int32, bool right, Tensor& result) { |
| 68 | + TORCH_CHECK(boundaries.dim() == 1, "boundaries tensor must be 1 dimension, but got dim(", boundaries.dim(), ")"); |
| 69 | + at::native::searchsorted_out_cpu(boundaries, self, out_int32, right, nullopt, nullopt, result); |
| 70 | + return result; |
| 71 | +} |
| 72 | +``` |
| 73 | +整体逻辑为: |
| 74 | +- 检查输入参数`boundaries`。 |
| 75 | +- 然后直接利用`searchsorted_out_cpu`返回结果。 |
| 76 | +
|
| 77 | +## Tensorflow |
| 78 | +Tensorflow`tft.bucketize( |
| 79 | + x: common_types.ConsistentTensorType, |
| 80 | + num_buckets: int, |
| 81 | + epsilon: Optional[float] = None, |
| 82 | + weights: Optional[tf.Tensor] = None, |
| 83 | + elementwise: bool = False, |
| 84 | + name: Optional[str] = None |
| 85 | +) -> common_types.ConsistentTensorType`。在Tensorflow中,介绍为: |
| 86 | +Returns a bucketized column, with a bucket index assigned to each input. |
| 87 | +
|
| 88 | +### 实现方法 |
| 89 | +在实现方法上,Tensorflow的API参数设计于Numpy和Pytorch都不大相同,[代码位置](https://github.com/tensorflow/transform/blob/v1.9.0/tensorflow_transform/mappers.py#L1690-L1770)。这里就不具体分析其核心代码了,因为和我们想要实现的功能有很大的差距。 |
| 90 | +
|
| 91 | +
|
| 92 | +# 四、对比分析 |
| 93 | +- 使用场景与功能:Pytorch会比Numpy更贴和我们想要实现的功能,因为Pytorch也是仅针对1-D Tensor,而Numpy支持多维。 |
| 94 | +
|
| 95 | +# 五、方案设计 |
| 96 | +## 命名与参数设计 |
| 97 | +API设计为`paddle.bucketize(x, sorted_sequence, out_int32=False, right=False, name=None)` |
| 98 | +命名与参数顺序为:形参名`input`->`x`, 与paddle其他API保持一致性,不影响实际功能使用。 |
| 99 | +参数类型中,`x`为N-D Tensor,`sorted_sequence`为1-D Tensor。 |
| 100 | +
|
| 101 | +## 底层OP设计 |
| 102 | +使用已有API组合实现,不再单独设计OP。 |
| 103 | +
|
| 104 | +## API实现方案 |
| 105 | +主要按下列步骤进行实现,实现位置为`paddle/tensor/math.py`与`searchsorted`方法放在一起: |
| 106 | +1. 使用`len(sorted_sequence)`检验参数`sorted_sequence`的维度。 |
| 107 | +2. 使用`paddle.searchsorted`得到输入的桶索引。 |
| 108 | +
|
| 109 | +
|
| 110 | +# 六、测试和验收的考量 |
| 111 | +测试考虑的case如下: |
| 112 | +
|
| 113 | +- 和numpy结果的数值的一致性, `paddle.bucketize`,和`numpy.searchsorted`结果是否一致; |
| 114 | +- 参数`right`为True和False时输出的正确性; |
| 115 | +- `out_int32`为True和False时输出dtype正确性; |
| 116 | +- 未输入`right`时的输出正确性; |
| 117 | +- 未输入`out_int32`时的输出正确性; |
| 118 | +- 错误检查:输入`x`不是Tensor时,能否正确抛出错误; |
| 119 | +- 错误检查:输入`sorted_sequence`不是一维张量时,能否正确抛出错误; |
| 120 | +- 错误检查:未输入`x`和`sorted_sequence`时,能否正确抛出错误; |
| 121 | +
|
| 122 | +# 七、可行性分析及规划排期 |
| 123 | +
|
| 124 | +方案主要依赖现有paddle api组合而成,且依赖的`paddle.searchsorted`已经在 Paddle repo 的 python/paddle/tensor/search.py [目录中](https://github.com/PaddlePaddle/Paddle/blob/release/2.3/python/paddle/tensor/search.py#L910)。工期上可以满足在当前版本周期内开发完成。 |
| 125 | +
|
| 126 | +# 八、影响面 |
| 127 | +为独立新增API,对其他模块没有影响 |
| 128 | +
|
| 129 | +# 名词解释 |
| 130 | +无 |
| 131 | +# 附件及参考资料 |
| 132 | +无 |
| 133 | +
|
0 commit comments