1 //
2 // Copyright © 2019 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include "SpaceToDepthEndToEndTestImpl.hpp"
7 #include "ResolveType.hpp"
8 #include "EndToEndTestImpl.hpp"
9
10 #include <armnn/INetwork.hpp>
11
12 #include <armnnUtils/Permute.hpp>
13 #include <armnnUtils/DataLayoutIndexed.hpp>
14
15 #include <armnnTestUtils/DataLayoutUtils.hpp>
16
17 #include <TestUtils.hpp>
18
19 #include <doctest/doctest.h>
20
21 namespace
22 {
23
24 template<typename armnn::DataType DataType>
CreateSpaceToDepthNetwork(const armnn::TensorShape & inputShape,const armnn::TensorShape & outputShape,const armnn::DataLayout dataLayout,unsigned int blockSize,const float qScale=1.0f,const int32_t qOffset=0)25 armnn::INetworkPtr CreateSpaceToDepthNetwork(const armnn::TensorShape& inputShape,
26 const armnn::TensorShape& outputShape,
27 const armnn::DataLayout dataLayout,
28 unsigned int blockSize,
29 const float qScale = 1.0f,
30 const int32_t qOffset = 0)
31 {
32 using namespace armnn;
33
34 // Builds up the structure of the network.
35 INetworkPtr net(INetwork::Create());
36
37 TensorInfo inputTensorInfo(inputShape, DataType, qScale, qOffset, true);
38
39 armnnUtils::DataLayoutIndexed dimensionIndices(dataLayout);
40 if (inputShape[dimensionIndices.GetHeightIndex()] % blockSize!=0
41 || inputShape[dimensionIndices.GetWidthIndex()] % blockSize!=0)
42 {
43 throw InvalidArgumentException("Input shape must be divisible by block size in all spatial dimensions");
44 }
45
46 SpaceToDepthDescriptor spaceToDepthDesc;
47 spaceToDepthDesc.m_BlockSize = blockSize;
48 spaceToDepthDesc.m_DataLayout = dataLayout;
49
50 IConnectableLayer* SpaceToDepth = net->AddSpaceToDepthLayer(spaceToDepthDesc, "SpaceToDepth");
51 IConnectableLayer* input = net->AddInputLayer(0, "input");
52 Connect(input, SpaceToDepth, inputTensorInfo, 0, 0);
53
54 TensorInfo outputTensorInfo(outputShape, DataType, qScale, qOffset);
55 IConnectableLayer* output = net->AddOutputLayer(0, "output");
56 Connect(SpaceToDepth, output, outputTensorInfo, 0, 0);
57
58 return net;
59 }
60
SpaceToDepthEndToEnd(const std::vector<armnn::BackendId> & backends,const armnn::DataLayout & dataLayout,armnn::TensorInfo & inputTensorInfo,armnn::TensorInfo & outputTensorInfo,std::vector<float> & inputData,std::vector<float> & expectedOutputData,const unsigned int blockSize)61 void SpaceToDepthEndToEnd(const std::vector<armnn::BackendId>& backends,
62 const armnn::DataLayout& dataLayout,
63 armnn::TensorInfo& inputTensorInfo,
64 armnn::TensorInfo& outputTensorInfo,
65 std::vector<float>& inputData,
66 std::vector<float>& expectedOutputData,
67 const unsigned int blockSize)
68 {
69 using namespace armnn;
70
71 if (dataLayout == DataLayout::NCHW)
72 {
73 PermuteTensorNhwcToNchw<float>(inputTensorInfo, inputData);
74 PermuteTensorNhwcToNchw<float>(outputTensorInfo, expectedOutputData);
75 }
76
77 // Builds up the structure of the network
78 INetworkPtr net = CreateSpaceToDepthNetwork<DataType::Float32>(
79 inputTensorInfo.GetShape(),
80 outputTensorInfo.GetShape(),
81 dataLayout,
82 blockSize);
83
84 CHECK(net);
85
86 std::map<int, std::vector<float>> inputTensorData = { { 0, inputData } };
87 std::map<int, std::vector<float>> expectedOutputTensorData = { { 0, expectedOutputData } };
88
89 EndToEndLayerTestImpl<DataType::Float32, DataType::Float32>(
90 move(net),
91 inputTensorData,
92 expectedOutputTensorData,
93 backends);
94 }
95
96 } // anonymous namespace
97
SpaceToDepthNhwcEndToEndTest1(const std::vector<armnn::BackendId> & defaultBackends)98 void SpaceToDepthNhwcEndToEndTest1(const std::vector<armnn::BackendId>& defaultBackends)
99 {
100 using namespace armnn;
101
102 const unsigned int blockSize = 2;
103
104 TensorShape inputShape{1, 2, 2, 1};
105 TensorInfo inputTensorInfo(inputShape, DataType::Float32, 0.0f, 0, true);
106
107 TensorShape outputShape{1, 1, 1, 4};
108 TensorInfo outputTensorInfo(outputShape, DataType::Float32);
109
110 std::vector<float> inputData = std::vector<float>(
111 {
112 1.0f, 2.0f, 3.0f, 4.0f
113 });
114
115 std::vector<float> expectedOutputData = std::vector<float>(
116 {
117 1.0f, 2.0f, 3.0f, 4.0f
118 });
119
120 SpaceToDepthEndToEnd(defaultBackends,
121 DataLayout::NHWC,
122 inputTensorInfo,
123 outputTensorInfo,
124 inputData,
125 expectedOutputData,
126 blockSize);
127 }
128
SpaceToDepthNchwEndToEndTest1(const std::vector<armnn::BackendId> & defaultBackends)129 void SpaceToDepthNchwEndToEndTest1(const std::vector<armnn::BackendId>& defaultBackends)
130 {
131 using namespace armnn;
132
133 const unsigned int blockSize = 2;
134
135 TensorShape inputShape{1, 2, 2, 1};
136 TensorInfo inputTensorInfo(inputShape, DataType::Float32, 0.0f, 0, true);
137
138 TensorShape outputShape{1, 1, 1, 4};
139 TensorInfo outputTensorInfo(outputShape, DataType::Float32);
140
141 std::vector<float> inputData = std::vector<float>(
142 {
143 1.0f, 2.0f, 3.0f, 4.0f
144 });
145
146 std::vector<float> expectedOutputData = std::vector<float>(
147 {
148 1.0f, 2.0f, 3.0f, 4.0f
149 });
150
151 SpaceToDepthEndToEnd(defaultBackends,
152 DataLayout::NCHW,
153 inputTensorInfo,
154 outputTensorInfo,
155 inputData,
156 expectedOutputData,
157 blockSize);
158 }
159
SpaceToDepthNhwcEndToEndTest2(const std::vector<armnn::BackendId> & defaultBackends)160 void SpaceToDepthNhwcEndToEndTest2(const std::vector<armnn::BackendId>& defaultBackends)
161 {
162 using namespace armnn;
163
164 const unsigned int blockSize = 2;
165
166 TensorShape inputShape{1, 2, 2, 2};
167 TensorShape outputShape{1, 1, 1, 8};
168
169 TensorInfo outputTensorInfo(outputShape, DataType::Float32);
170 TensorInfo inputTensorInfo(inputShape, DataType::Float32, 0.0f, 0, true);
171
172 std::vector<float> inputData = std::vector<float>(
173 {
174 1.4f, 2.3f, 3.2f, 4.1f, 5.4f, 6.3f, 7.2f, 8.1f
175 });
176
177 std::vector<float> expectedOutputData = std::vector<float>(
178 {
179 1.4f, 2.3f, 3.2f, 4.1f, 5.4f, 6.3f, 7.2f, 8.1f
180 });
181
182 SpaceToDepthEndToEnd(defaultBackends,
183 DataLayout::NHWC,
184 inputTensorInfo,
185 outputTensorInfo,
186 inputData,
187 expectedOutputData,
188 blockSize);
189 }
190
SpaceToDepthNchwEndToEndTest2(const std::vector<armnn::BackendId> & defaultBackends)191 void SpaceToDepthNchwEndToEndTest2(const std::vector<armnn::BackendId>& defaultBackends)
192 {
193 using namespace armnn;
194
195 const unsigned int blockSize = 2;
196
197 TensorShape inputShape{1, 2, 2, 2};
198 TensorShape outputShape{1, 1, 1, 8};
199
200 TensorInfo inputTensorInfo(inputShape, DataType::Float32, 0.0f, 0, true);
201 TensorInfo outputTensorInfo(outputShape, DataType::Float32);
202
203
204 std::vector<float> inputData = std::vector<float>(
205 {
206 1.4f, 2.3f, 3.2f, 4.1f, 5.4f, 6.3f, 7.2f, 8.1f
207 });
208
209 std::vector<float> expectedOutputData = std::vector<float>(
210 {
211 1.4f, 2.3f, 3.2f, 4.1f, 5.4f, 6.3f, 7.2f, 8.1f
212 });
213
214 SpaceToDepthEndToEnd(defaultBackends,
215 DataLayout::NCHW,
216 inputTensorInfo,
217 outputTensorInfo,
218 inputData,
219 expectedOutputData,
220 blockSize);
221 }
222