xref: /aosp_15_r20/external/ComputeLibrary/examples/neon_permute.cpp (revision c217d954acce2dbc11938adb493fc0abd69584f3)
1 /*
2  * Copyright (c) 2019 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #include "arm_compute/runtime/NEON/NEFunctions.h"
25 
26 #include "arm_compute/core/Types.h"
27 #include "utils/Utils.h"
28 
29 using namespace arm_compute;
30 using namespace utils;
31 
32 class NeonPermuteExample : public Example
33 {
34 public:
35     NeonPermuteExample() = default;
36 
do_setup(int,char **)37     bool do_setup(int, char **) override
38     {
39         // Initialise shapes
40         init_tensor(TensorShape(8U, 4U, 2U), tensor_nchw, DataType::U8, DataLayout::NCHW);
41         init_tensor(TensorShape(2U, 8U, 4U), tensor_nhwc, DataType::U8, DataLayout::NHWC);
42         init_tensor(TensorShape(8U, 4U, 2U), tensor_nchw_result, DataType::U8, DataLayout::NCHW);
43 
44         // Create the permutation vector to turn a NCHW tensor to NHWC.
45         // The input tensor is NCHW, which means that the fastest changing coordinate is W=8U.
46         // For permutation vectors the fastest changing coordinate is the one on the left too.
47         // Each element in the permutation vector specifies a mapping from the source tensor to the destination one, thus if we
48         // use 2U in the permutation vector's first element we are telling the function to move the channels to the fastest
49         // changing coordinate in the destination tensor.
50 
51         const PermutationVector vector_nchw_to_nhwc(2U, 0U, 1U);
52         permute_nhwc.configure(&tensor_nchw, &tensor_nhwc, vector_nchw_to_nhwc);
53 
54         // Allocate and fill tensors
55         tensor_nhwc.allocator()->allocate();
56         tensor_nchw.allocator()->allocate();
57         fill_tensor(tensor_nchw);
58 
59         // Demostrate autoconfigure for the output tensor
60         const PermutationVector vector_nhwc_to_nchw(1U, 2U, 0U);
61         permute_nchw.configure(&tensor_nhwc, &tensor_nchw_result, vector_nhwc_to_nchw);
62         tensor_nchw_result.allocator()->allocate();
63 
64         return true;
65     }
do_run()66     void do_run() override
67     {
68         permute_nhwc.run();
69         permute_nchw.run();
70     }
do_teardown()71     void do_teardown() override
72     {
73 #if ARM_COMPUTE_DEBUG_ENABLED
74         std::cout << "Tensor NCHW" << std::endl;
75         tensor_nchw.print(std::cout);
76         std::cout << "Tensor NHWC" << std::endl;
77         tensor_nhwc.print(std::cout);
78 #endif // ARM_COMPUTE_DEBUG_ENABLED
79     }
80 
81 private:
validate_result(const Tensor & reference,const Tensor & result)82     void validate_result(const Tensor &reference, const Tensor &result)
83     {
84         Window window;
85         window.use_tensor_dimensions(reference.info()->tensor_shape());
86         Iterator ref_it(&reference, window);
87         Iterator res_it(&result, window);
88         execute_window_loop(window, [&](const Coordinates &)
89         {
90             assert(*reinterpret_cast<unsigned char *>(ref_it.ptr()) == *reinterpret_cast<unsigned char *>(res_it.ptr()));
91         },
92         ref_it, res_it);
93     }
94 
fill_tensor(Tensor & tensor)95     void fill_tensor(Tensor &tensor)
96     {
97         Window window;
98         window.use_tensor_dimensions(tensor.info()->tensor_shape());
99         Iterator      tensor_it(&tensor, window);
100         unsigned char val(0);
101         execute_window_loop(window, [&](const Coordinates &)
102         {
103             *reinterpret_cast<unsigned char *>(tensor_it.ptr()) = val++;
104         },
105         tensor_it);
106     }
init_tensor(const TensorShape shape,Tensor & tensor,DataType type,DataLayout layout)107     void init_tensor(const TensorShape shape, Tensor &tensor, DataType type, DataLayout layout)
108     {
109         tensor.allocator()->init(TensorInfo(shape, 1, type).set_data_layout(layout));
110     }
111 
112     Tensor    tensor_nchw{};
113     Tensor    tensor_nhwc{};
114     Tensor    tensor_nchw_result{};
115     NEPermute permute_nhwc{};
116     NEPermute permute_nchw{};
117 };
118 
119 /** Main program that instantiates a permute function example.
120  *
121  * @param[in] argc Number of arguments
122  * @param[in] argv Arguments
123  */
main(int argc,char ** argv)124 int main(int argc, char **argv)
125 {
126     return utils::run_example<NeonPermuteExample>(argc, argv);
127 }
128