From 4b807674509ea24b282cdf499d93e74e82c93244 Mon Sep 17 00:00:00 2001 From: hxzd5568 <40557101+hxzd5568@users.noreply.github.com> Date: Sun, 7 Aug 2022 00:09:33 +0800 Subject: [PATCH 1/5] add 20220807_api_design_for_flip.md --- .../CINN/APIs/20220807_api_design_for_flip.md | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 rfcs/CINN/APIs/20220807_api_design_for_flip.md diff --git a/rfcs/CINN/APIs/20220807_api_design_for_flip.md b/rfcs/CINN/APIs/20220807_api_design_for_flip.md new file mode 100644 index 000000000..1000509c8 --- /dev/null +++ b/rfcs/CINN/APIs/20220807_api_design_for_flip.md @@ -0,0 +1,153 @@ +# CINN flip 设计文档 + +| API名称 | 新增API名称 | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| 提交作者 | 小小夏 | +| 提交时间 | 2022-08-06 | +| 版本号 | V1.0 | +| 依赖飞桨版本 | develop | +| 文件名 | 20220807_api_design_for_flip.md
| + + +# 一、概述 + +## 1、相关背景 + +flip是众多神经网络编译器中基础的算子,属于injection级别,它将输入的指定维度上进行元素翻转。 + +## 2、功能目标 + +实现flip功能 + +## 3、意义 + +为神经网络编译器 CINN 增加基础算子flip + +# 二、飞桨现状 + +CINN框架目前不支持此功能,暂时没有比较好的 API 替代,因此有必要实现flip算子 + + +# 三、业内方案调研 + + + +tensorflow中调用了numpy的flip实现: + +```python +@array_function_dispatch(_flip_dispatcher) +def flip(m, axis=None): + """ + Reverse the order of elements in an array along the given axis. + The shape of the array is preserved, but the elements are reordered. + .. versionadded:: 1.12.0 + Parameters + ---------- + m : array_like + Input array. + axis : None or int or tuple of ints, optional + Axis or axes along which to flip over. The default, + axis=None, will flip over all of the axes of the input array. + If axis is negative it counts from the last to the first axis. + If axis is a tuple of ints, flipping is performed on all of the axes + specified in the tuple. + .. versionchanged:: 1.15.0 + None and tuples of axes are supported + Returns + ------- + out : array_like + A view of `m` with the entries of axis reversed. Since a view is + returned, this operation is done in constant time. + See Also + -------- + flipud : Flip an array vertically (axis=0). + fliplr : Flip an array horizontally (axis=1). + Notes + ----- + flip(m, 0) is equivalent to flipud(m). + flip(m, 1) is equivalent to fliplr(m). + flip(m, n) corresponds to ``m[...,::-1,...]`` with ``::-1`` at position n. + flip(m) corresponds to ``m[::-1,::-1,...,::-1]`` with ``::-1`` at all + positions. + flip(m, (0, 1)) corresponds to ``m[::-1,::-1,...]`` with ``::-1`` at + position 0 and position 1. + """ + if not hasattr(m, 'ndim'): + m = asarray(m) + if axis is None: + indexer = (np.s_[::-1],) * m.ndim + else: + axis = _nx.normalize_axis_tuple(axis, m.ndim) + indexer = [np.s_[:]] * m.ndim + for ax in axis: + indexer[ax] = np.s_[::-1] + indexer = tuple(indexer) + return m[indexer] +``` + +该方案特点是实际返回了一个原始array的视图,不需要新的空间,时间复杂度低。 + +pytorch则返回了一个新的tensor: + +``` +torch.flip(input, dims) → Tensor +Reverse the order of a n-D tensor along given axis in dims. + +NOTE + +torch.flip makes a copy of input’s data. This is different from NumPy’s np.flip, which returns a view in constant time. Since copying a tensor’s data is more work than viewing that data, torch.flip is expected to be slower than np.flip. +} +``` + +# 四、对比分析 + +在业界,pytorch和numpy的实现基本相同,但前者产生一个数据拷贝,而后者仅仅返回一个视图。 + +# 五、设计思路与实现方案 + +可以实现对所有维度,单个维度,多个指定维度的数据转化,并返回一个新的拷贝。 + +## 命名与参数设计 + +- A:输入张量 +- dim:需要翻转的维度(可以为None,int ,tuple)缺省时表示翻转所有维度 + +## 底层OP设计 + +1. 在 `cinn/hlir/op/contrib/flip.h` 里声明`flip`算子。 +2. 在 `cinn/hlir/op/contrib/flip.cc` 里实现`flip`算子和 `strategy`。 + +## API实现方案 + +实现目标为对于张量 A = (M, N, K),flip( A, a_max, a_min) 结果尺寸为 A = (M, N, K) 不变,但其中的数值发生变化,任一元素的值都在[ a_min, a_max ]的区间范围内 + +1. 在 `cinn/frontend/net_build.h` 里声明 `NetBuilder::flip`。 +2. 在 `cinn/frontend/net_build.cc` 里实现 `NetBuilder::flip`。 +3. 在 `cinn/pybind/frontend` 对 Python 类 `NetBuilder` 添加 `flip` 接口,并绑定到 `NetBuilder::flip`。 +4. 上层 `load_paddle_model` 调用提交到 `cinn/frontend/paddle_model_to_program.h` 和 `.cc` 文件下。 + +通过使用 Builder 类的方法调用 flip。 + +```python +builder = CinnBuilder("test_basic") +a = builder.create_input(Float(32), (32, 16, 16), "A") +b = builder.flip(a,1) +b = builder.flip(a,(0,1)) +b = builder.flip(a) +``` + +# 六、测试和验收的考量 + +1. 提供基础的 demo 文件。 + +2. 在`cinn/hlir/op/contrib/flip_test.cc`中添加对底层OP进行测试的代码,在`cinn/frontend/net_builder_test.cc`中添加对前端的测试。 +3. 提交 API 使用方法到相应的文档中。 + +# 七、可行性分析和排期规划 + +- 可行性分析:非常可行 +- 排期规划:底层OP设计已完成,API、测试和文档部分预计15天内完成 + +# 八、影响面 + +对其他模块无影响。 From 4054683d97b326ff7acb23ba52a69e6ea92e5aad Mon Sep 17 00:00:00 2001 From: hxzd5568 <40557101+hxzd5568@users.noreply.github.com> Date: Sun, 7 Aug 2022 00:19:57 +0800 Subject: [PATCH 2/5] Update 20220807_api_design_for_flip.md --- rfcs/CINN/APIs/20220807_api_design_for_flip.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/CINN/APIs/20220807_api_design_for_flip.md b/rfcs/CINN/APIs/20220807_api_design_for_flip.md index 1000509c8..483ca65a3 100644 --- a/rfcs/CINN/APIs/20220807_api_design_for_flip.md +++ b/rfcs/CINN/APIs/20220807_api_design_for_flip.md @@ -119,7 +119,7 @@ torch.flip makes a copy of input’s data. This is different from NumPy’s np.f ## API实现方案 -实现目标为对于张量 A = (M, N, K),flip( A, a_max, a_min) 结果尺寸为 A = (M, N, K) 不变,但其中的数值发生变化,任一元素的值都在[ a_min, a_max ]的区间范围内 +实现目标为对于张量 A = (M, N, K),flip( A, dim) 结果尺寸为 A = (M, N, K) 不变,但其中的数值顺序发生变化,dim维度上的数据发生翻转。 1. 在 `cinn/frontend/net_build.h` 里声明 `NetBuilder::flip`。 2. 在 `cinn/frontend/net_build.cc` 里实现 `NetBuilder::flip`。 From c9c355aae19fd0e911109037a35460243733f612 Mon Sep 17 00:00:00 2001 From: hxzd5568 <40557101+hxzd5568@users.noreply.github.com> Date: Thu, 11 Aug 2022 14:07:10 +0800 Subject: [PATCH 3/5] Update 20220807_api_design_for_flip.md --- .../CINN/APIs/20220807_api_design_for_flip.md | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/rfcs/CINN/APIs/20220807_api_design_for_flip.md b/rfcs/CINN/APIs/20220807_api_design_for_flip.md index 483ca65a3..2c8bbe693 100644 --- a/rfcs/CINN/APIs/20220807_api_design_for_flip.md +++ b/rfcs/CINN/APIs/20220807_api_design_for_flip.md @@ -1,6 +1,6 @@ # CINN flip 设计文档 -| API名称 | 新增API名称 | +| API名称 | flip | | ------------------------------------------------------------ | ------------------------------------------------------------ | | 提交作者 | 小小夏 | | 提交时间 | 2022-08-06 | @@ -13,11 +13,43 @@ ## 1、相关背景 -flip是众多神经网络编译器中基础的算子,属于injection级别,它将输入的指定维度上进行元素翻转。 +flip是众多神经网络编译器中基础的算子,属于injective类型的算子,它将输入的指定维度上进行元素翻转。(Injective operator, can always injectively map output axis to a single input axis. All injective operator can still be safely fused to injective and reduction.) ## 2、功能目标 -实现flip功能 +实现flip功能,在指定维度翻转元素顺序。Reverse the order of elements in an array along the given axis. +可以实现对所有维度,单个维度,多个指定维度的数据转化,并返回一个新的拷贝。输入需要处理的张量以及需要翻转的维度(可以为None,int ,tuple)缺省时表示翻转所有维度。 +``` +example + + A = [[[0, 1], + [2, 3]], + [[4, 5], + [6, 7]]] + + flip(A, 0) + >>>[[[4, 5], + [6, 7]], + [[0, 1], + [2, 3]]] + flip(A, 1) + >>>[[[2, 3], + [0, 1]], + [[6, 7], + [4, 5]]] + flip(A) + >>>[[[7, 6], + [5, 4]], + [[3, 2], + [1, 0]]] + flip(A, (0, 2)) + >>>[[[5, 4], + [7, 6]], + [[1, 0], + [3, 2]]] + + +``` ## 3、意义 From 5a90ddba1c966c79a80a7b01c2b34ee594ac9dbb Mon Sep 17 00:00:00 2001 From: hxzd5568 <40557101+hxzd5568@users.noreply.github.com> Date: Thu, 11 Aug 2022 14:09:32 +0800 Subject: [PATCH 4/5] Update 20220807_api_design_for_flip.md --- rfcs/CINN/APIs/20220807_api_design_for_flip.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rfcs/CINN/APIs/20220807_api_design_for_flip.md b/rfcs/CINN/APIs/20220807_api_design_for_flip.md index 2c8bbe693..322f58df4 100644 --- a/rfcs/CINN/APIs/20220807_api_design_for_flip.md +++ b/rfcs/CINN/APIs/20220807_api_design_for_flip.md @@ -17,7 +17,8 @@ flip是众多神经网络编译器中基础的算子,属于injective类型的 ## 2、功能目标 -实现flip功能,在指定维度翻转元素顺序。Reverse the order of elements in an array along the given axis. +flip(tensor,dim):Reverse the order of elements in an array along the given axis. +实现flip功能,在指定维度翻转元素顺序。 可以实现对所有维度,单个维度,多个指定维度的数据转化,并返回一个新的拷贝。输入需要处理的张量以及需要翻转的维度(可以为None,int ,tuple)缺省时表示翻转所有维度。 ``` example From a73bd72adc91a32745a6c4adc887401070686f8a Mon Sep 17 00:00:00 2001 From: hxzd5568 <40557101+hxzd5568@users.noreply.github.com> Date: Tue, 16 Aug 2022 19:16:06 +0800 Subject: [PATCH 5/5] Update 20220807_api_design_for_flip.md --- .../CINN/APIs/20220807_api_design_for_flip.md | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/rfcs/CINN/APIs/20220807_api_design_for_flip.md b/rfcs/CINN/APIs/20220807_api_design_for_flip.md index 322f58df4..09925f5d0 100644 --- a/rfcs/CINN/APIs/20220807_api_design_for_flip.md +++ b/rfcs/CINN/APIs/20220807_api_design_for_flip.md @@ -13,40 +13,40 @@ ## 1、相关背景 -flip是众多神经网络编译器中基础的算子,属于injective类型的算子,它将输入的指定维度上进行元素翻转。(Injective operator, can always injectively map output axis to a single input axis. All injective operator can still be safely fused to injective and reduction.) +flip是众多神经网络编译器中基础的算子,该算子代表的数学函数属于injection类型。它将输入的指定维度上进行元素翻转。(Injective operator, can always injectively map output axis to a single input axis. All injective operator can still be safely fused to injective and reduction.) ## 2、功能目标 -flip(tensor,dim):Reverse the order of elements in an array along the given axis. +flip(tensor, dim):Reverse the order of elements in an array along the given axis. 实现flip功能,在指定维度翻转元素顺序。 -可以实现对所有维度,单个维度,多个指定维度的数据转化,并返回一个新的拷贝。输入需要处理的张量以及需要翻转的维度(可以为None,int ,tuple)缺省时表示翻转所有维度。 +可以实现对所有维度,单个维度,多个指定维度的数据转化,并返回一个新的拷贝。输入需要处理的张量以及需要翻转的维度(可以为None, int, tuple)缺省时表示翻转所有维度。 ``` example - A = [[[0, 1], - [2, 3]], - [[4, 5], + A = [[[0, 1], + [2, 3]], + [[4, 5], [6, 7]]] flip(A, 0) - >>>[[[4, 5], - [6, 7]], - [[0, 1], + >>>[[[4, 5], + [6, 7]], + [[0, 1], [2, 3]]] flip(A, 1) - >>>[[[2, 3], - [0, 1]], - [[6, 7], + >>>[[[2, 3], + [0, 1]], + [[6, 7], [4, 5]]] flip(A) - >>>[[[7, 6], - [5, 4]], - [[3, 2], + >>>[[[7, 6], + [5, 4]], + [[3, 2], [1, 0]]] flip(A, (0, 2)) - >>>[[[5, 4], - [7, 6]], - [[1, 0], + >>>[[[5, 4], + [7, 6]], + [[1, 0], [3, 2]]] @@ -79,7 +79,7 @@ def flip(m, axis=None): m : array_like Input array. axis : None or int or tuple of ints, optional - Axis or axes along which to flip over. The default, + Axis or axes along which to flip over. The default, axis=None, will flip over all of the axes of the input array. If axis is negative it counts from the last to the first axis. If axis is a tuple of ints, flipping is performed on all of the axes @@ -99,16 +99,16 @@ def flip(m, axis=None): ----- flip(m, 0) is equivalent to flipud(m). flip(m, 1) is equivalent to fliplr(m). - flip(m, n) corresponds to ``m[...,::-1,...]`` with ``::-1`` at position n. - flip(m) corresponds to ``m[::-1,::-1,...,::-1]`` with ``::-1`` at all + flip(m, n) corresponds to ``m[..., ::-1, ...]`` with ``::-1`` at position n. + flip(m) corresponds to ``m[::-1, ::-1, ..., ::-1]`` with ``::-1`` at all positions. - flip(m, (0, 1)) corresponds to ``m[::-1,::-1,...]`` with ``::-1`` at + flip(m, (0, 1)) corresponds to ``m[::-1, ::-1, ...]`` with ``::-1`` at position 0 and position 1. """ if not hasattr(m, 'ndim'): m = asarray(m) if axis is None: - indexer = (np.s_[::-1],) * m.ndim + indexer = (np.s_[::-1], ) * m.ndim else: axis = _nx.normalize_axis_tuple(axis, m.ndim) indexer = [np.s_[:]] * m.ndim @@ -128,7 +128,7 @@ Reverse the order of a n-D tensor along given axis in dims. NOTE -torch.flip makes a copy of input’s data. This is different from NumPy’s np.flip, which returns a view in constant time. Since copying a tensor’s data is more work than viewing that data, torch.flip is expected to be slower than np.flip. +torch.flip makes a copy of input's data. This is different from NumPy's np.flip, which returns a view in constant time. Since copying a tensor's data is more work than viewing that data, torch.flip is expected to be slower than np.flip. } ``` @@ -143,7 +143,7 @@ torch.flip makes a copy of input’s data. This is different from NumPy’s np.f ## 命名与参数设计 - A:输入张量 -- dim:需要翻转的维度(可以为None,int ,tuple)缺省时表示翻转所有维度 +- dim:需要翻转的维度(可以为None, int, tuple)缺省时表示翻转所有维度 ## 底层OP设计 @@ -164,15 +164,14 @@ torch.flip makes a copy of input’s data. This is different from NumPy’s np.f ```python builder = CinnBuilder("test_basic") a = builder.create_input(Float(32), (32, 16, 16), "A") -b = builder.flip(a,1) -b = builder.flip(a,(0,1)) +b = builder.flip(a, 1) +b = builder.flip(a, (0, 1)) b = builder.flip(a) ``` # 六、测试和验收的考量 1. 提供基础的 demo 文件。 - 2. 在`cinn/hlir/op/contrib/flip_test.cc`中添加对底层OP进行测试的代码,在`cinn/frontend/net_builder_test.cc`中添加对前端的测试。 3. 提交 API 使用方法到相应的文档中。