blob: e70a1a275f3d06a0ddddd4b903fc431f1b3a7057 [file] [log] [blame]
Anthony Barbier2a07e182017-08-04 18:20:27 +01001/*
Giorgio Arenaa66eaa22017-12-21 19:50:06 +00002 * Copyright (c) 2017-2018 ARM Limited.
Anthony Barbier2a07e182017-08-04 18:20:27 +01003 *
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#ifndef __ARM_COMPUTE_GRAPH_UTILS_H__
25#define __ARM_COMPUTE_GRAPH_UTILS_H__
26
Michalis Spyrou53b405f2017-09-27 15:55:31 +010027#include "arm_compute/core/PixelValue.h"
Gian Marcobfa3b522017-12-12 10:08:38 +000028#include "arm_compute/graph/Graph.h"
Anthony Barbier2a07e182017-08-04 18:20:27 +010029#include "arm_compute/graph/ITensorAccessor.h"
30#include "arm_compute/graph/Types.h"
31
Georgios Pinitasd8734b52017-12-22 15:27:52 +000032#include "arm_compute/core/CL/OpenCL.h"
33
34#include "arm_compute/graph2/Types.h"
35
Georgios Pinitas140fdc72018-02-16 11:42:38 +000036#include <array>
Michalis Spyrou53b405f2017-09-27 15:55:31 +010037#include <random>
Gian Marco44ec2e72017-10-19 14:13:38 +010038#include <string>
39#include <vector>
Michalis Spyrou53b405f2017-09-27 15:55:31 +010040
Anthony Barbier2a07e182017-08-04 18:20:27 +010041namespace arm_compute
42{
43namespace graph_utils
44{
Georgios Pinitas140fdc72018-02-16 11:42:38 +000045/** Preprocessor interface **/
46class IPreprocessor
47{
48public:
Alex Gildayc357c472018-03-21 13:54:09 +000049 /** Default destructor. */
50 virtual ~IPreprocessor() = default;
51 /** Preprocess the given tensor.
52 *
53 * @param[in] tensor Tensor to preprocess.
54 */
Georgios Pinitas140fdc72018-02-16 11:42:38 +000055 virtual void preprocess(ITensor &tensor) = 0;
56};
57
58/** Caffe preproccessor */
59class CaffePreproccessor : public IPreprocessor
60{
61public:
62 /** Default Constructor
63 *
64 * @param mean Mean array in RGB ordering
65 * @param bgr Boolean specifying if the preprocessing should assume BGR format
66 */
67 CaffePreproccessor(std::array<float, 3> mean = std::array<float, 3> { { 0, 0, 0 } }, bool bgr = true);
68 void preprocess(ITensor &tensor) override;
69
70private:
71 std::array<float, 3> _mean;
72 bool _bgr;
73};
74
75/** TF preproccessor */
76class TFPreproccessor : public IPreprocessor
77{
78public:
79 void preprocess(ITensor &tensor) override;
80};
81
Anthony Barbier2a07e182017-08-04 18:20:27 +010082/** PPM writer class */
83class PPMWriter : public graph::ITensorAccessor
84{
85public:
86 /** Constructor
87 *
88 * @param[in] name PPM file name
89 * @param[in] maximum Maximum elements to access
90 */
91 PPMWriter(std::string name, unsigned int maximum = 1);
92 /** Allows instances to move constructed */
93 PPMWriter(PPMWriter &&) = default;
94
95 // Inherited methods overriden:
96 bool access_tensor(ITensor &tensor) override;
97
98private:
99 const std::string _name;
100 unsigned int _iterator;
101 unsigned int _maximum;
102};
103
104/** Dummy accessor class */
Michalis Spyrou53b405f2017-09-27 15:55:31 +0100105class DummyAccessor final : public graph::ITensorAccessor
Anthony Barbier2a07e182017-08-04 18:20:27 +0100106{
107public:
108 /** Constructor
109 *
110 * @param[in] maximum Maximum elements to write
111 */
112 DummyAccessor(unsigned int maximum = 1);
113 /** Allows instances to move constructed */
114 DummyAccessor(DummyAccessor &&) = default;
115
116 // Inherited methods overriden:
117 bool access_tensor(ITensor &tensor) override;
118
119private:
120 unsigned int _iterator;
121 unsigned int _maximum;
122};
123
Gian Marco44ec2e72017-10-19 14:13:38 +0100124/** PPM accessor class */
125class PPMAccessor final : public graph::ITensorAccessor
126{
127public:
128 /** Constructor
129 *
Georgios Pinitas140fdc72018-02-16 11:42:38 +0000130 * @param[in] ppm_path Path to PPM file
131 * @param[in] bgr (Optional) Fill the first plane with blue channel (default = false)
132 * @param[in] preprocessor (Optional) PPM pre-processing object
Gian Marco44ec2e72017-10-19 14:13:38 +0100133 */
Georgios Pinitas140fdc72018-02-16 11:42:38 +0000134 PPMAccessor(std::string ppm_path, bool bgr = true, std::unique_ptr<IPreprocessor> preprocessor = nullptr);
Gian Marco44ec2e72017-10-19 14:13:38 +0100135 /** Allow instances of this class to be move constructed */
136 PPMAccessor(PPMAccessor &&) = default;
137
138 // Inherited methods overriden:
139 bool access_tensor(ITensor &tensor) override;
140
141private:
Georgios Pinitas140fdc72018-02-16 11:42:38 +0000142 const std::string _ppm_path;
143 const bool _bgr;
144 std::unique_ptr<IPreprocessor> _preprocessor;
Gian Marco44ec2e72017-10-19 14:13:38 +0100145};
146
147/** Result accessor class */
148class TopNPredictionsAccessor final : public graph::ITensorAccessor
149{
150public:
151 /** Constructor
152 *
153 * @param[in] labels_path Path to labels text file.
154 * @param[in] top_n (Optional) Number of output classes to print
155 * @param[out] output_stream (Optional) Output stream
156 */
157 TopNPredictionsAccessor(const std::string &labels_path, size_t top_n = 5, std::ostream &output_stream = std::cout);
158 /** Allow instances of this class to be move constructed */
159 TopNPredictionsAccessor(TopNPredictionsAccessor &&) = default;
160 /** Prevent instances of this class from being copied (As this class contains pointers) */
161 TopNPredictionsAccessor(const TopNPredictionsAccessor &) = delete;
162 /** Prevent instances of this class from being copied (As this class contains pointers) */
163 TopNPredictionsAccessor &operator=(const TopNPredictionsAccessor &) = delete;
164
165 // Inherited methods overriden:
166 bool access_tensor(ITensor &tensor) override;
167
168private:
Giorgio Arenaa66eaa22017-12-21 19:50:06 +0000169 template <typename T>
170 void access_predictions_tensor(ITensor &tensor);
171
Gian Marco44ec2e72017-10-19 14:13:38 +0100172 std::vector<std::string> _labels;
173 std::ostream &_output_stream;
174 size_t _top_n;
175};
176
Michalis Spyrou53b405f2017-09-27 15:55:31 +0100177/** Random accessor class */
178class RandomAccessor final : public graph::ITensorAccessor
179{
180public:
181 /** Constructor
182 *
183 * @param[in] lower Lower bound value.
184 * @param[in] upper Upper bound value.
185 * @param[in] seed (Optional) Seed used to initialise the random number generator.
186 */
187 RandomAccessor(PixelValue lower, PixelValue upper, const std::random_device::result_type seed = 0);
188 /** Allows instances to move constructed */
189 RandomAccessor(RandomAccessor &&) = default;
190
191 // Inherited methods overriden:
192 bool access_tensor(ITensor &tensor) override;
193
194private:
195 template <typename T, typename D>
196 void fill(ITensor &tensor, D &&distribution);
197 PixelValue _lower;
198 PixelValue _upper;
199 std::random_device::result_type _seed;
200};
201
Anthony Barbier2a07e182017-08-04 18:20:27 +0100202/** Numpy Binary loader class*/
Michalis Spyrou53b405f2017-09-27 15:55:31 +0100203class NumPyBinLoader final : public graph::ITensorAccessor
Anthony Barbier2a07e182017-08-04 18:20:27 +0100204{
205public:
206 /** Default Constructor
207 *
208 * @param filename Binary file name
209 */
210 NumPyBinLoader(std::string filename);
211 /** Allows instances to move constructed */
212 NumPyBinLoader(NumPyBinLoader &&) = default;
213
214 // Inherited methods overriden:
215 bool access_tensor(ITensor &tensor) override;
216
217private:
218 const std::string _filename;
219};
Isabella Gottardia4c61882017-11-03 12:11:55 +0000220
Georgios Pinitas652bde52018-01-10 15:33:28 +0000221/** Generates appropriate random accessor
222 *
223 * @param[in] lower Lower random values bound
224 * @param[in] upper Upper random values bound
225 * @param[in] seed Random generator seed
226 *
227 * @return A ramdom accessor
228 */
229inline std::unique_ptr<graph::ITensorAccessor> get_random_accessor(PixelValue lower, PixelValue upper, const std::random_device::result_type seed = 0)
230{
231 return arm_compute::support::cpp14::make_unique<RandomAccessor>(lower, upper, seed);
232}
233
Isabella Gottardia4c61882017-11-03 12:11:55 +0000234/** Generates appropriate weights accessor according to the specified path
235 *
236 * @note If path is empty will generate a DummyAccessor else will generate a NumPyBinLoader
237 *
238 * @param[in] path Path to the data files
239 * @param[in] data_file Relative path to the data files from path
240 *
241 * @return An appropriate tensor accessor
242 */
243inline std::unique_ptr<graph::ITensorAccessor> get_weights_accessor(const std::string &path, const std::string &data_file)
244{
245 if(path.empty())
246 {
247 return arm_compute::support::cpp14::make_unique<DummyAccessor>();
248 }
249 else
250 {
251 return arm_compute::support::cpp14::make_unique<NumPyBinLoader>(path + data_file);
252 }
253}
254
255/** Generates appropriate input accessor according to the specified ppm_path
256 *
257 * @note If ppm_path is empty will generate a DummyAccessor else will generate a PPMAccessor
258 *
Georgios Pinitas140fdc72018-02-16 11:42:38 +0000259 * @param[in] ppm_path Path to PPM file
260 * @param[in] preprocessor Preproccessor object
261 * @param[in] bgr (Optional) Fill the first plane with blue channel (default = true)
Isabella Gottardia4c61882017-11-03 12:11:55 +0000262 *
263 * @return An appropriate tensor accessor
264 */
Georgios Pinitas140fdc72018-02-16 11:42:38 +0000265inline std::unique_ptr<graph::ITensorAccessor> get_input_accessor(const std::string &ppm_path,
266 std::unique_ptr<IPreprocessor> preprocessor = nullptr,
267 bool bgr = true)
Isabella Gottardia4c61882017-11-03 12:11:55 +0000268{
269 if(ppm_path.empty())
270 {
271 return arm_compute::support::cpp14::make_unique<DummyAccessor>();
272 }
273 else
274 {
Georgios Pinitas140fdc72018-02-16 11:42:38 +0000275 return arm_compute::support::cpp14::make_unique<PPMAccessor>(ppm_path, bgr, std::move(preprocessor));
Isabella Gottardia4c61882017-11-03 12:11:55 +0000276 }
277}
278
Gian Marcobfa3b522017-12-12 10:08:38 +0000279/** Utility function to return the TargetHint
280 *
Michele Di Giorgioe3fba0a2018-02-14 14:18:01 +0000281 * @param[in] target Integer value which expresses the selected target. Must be 0 for NEON, 1 for OpenCL or 2 for OpenCL with Tuner
Gian Marcobfa3b522017-12-12 10:08:38 +0000282 *
283 * @return the TargetHint
284 */
285inline graph::TargetHint set_target_hint(int target)
286{
Michele Di Giorgioe3fba0a2018-02-14 14:18:01 +0000287 ARM_COMPUTE_ERROR_ON_MSG(target > 2, "Invalid target. Target must be 0 (NEON), 1 (OpenCL) or 2 (OpenCL with Tuner)");
288 if((target == 1 || target == 2) && graph::Graph::opencl_is_available())
Gian Marcobfa3b522017-12-12 10:08:38 +0000289 {
290 // If type of target is OpenCL, check if OpenCL is available and initialize the scheduler
291 return graph::TargetHint::OPENCL;
292 }
293 else
294 {
295 return graph::TargetHint::NEON;
296 }
297}
298
Isabella Gottardia4c61882017-11-03 12:11:55 +0000299/** Generates appropriate output accessor according to the specified labels_path
300 *
301 * @note If labels_path is empty will generate a DummyAccessor else will generate a TopNPredictionsAccessor
302 *
303 * @param[in] labels_path Path to labels text file
304 * @param[in] top_n (Optional) Number of output classes to print
305 * @param[out] output_stream (Optional) Output stream
306 *
307 * @return An appropriate tensor accessor
308 */
309inline std::unique_ptr<graph::ITensorAccessor> get_output_accessor(const std::string &labels_path, size_t top_n = 5, std::ostream &output_stream = std::cout)
310{
311 if(labels_path.empty())
312 {
Anthony Barbiere1a905a2017-12-22 13:53:46 +0000313 return arm_compute::support::cpp14::make_unique<DummyAccessor>(0);
Isabella Gottardia4c61882017-11-03 12:11:55 +0000314 }
315 else
316 {
317 return arm_compute::support::cpp14::make_unique<TopNPredictionsAccessor>(labels_path, top_n, output_stream);
318 }
319}
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000320
321/** Utility function to return the TargetHint
322 *
323 * @param[in] target Integer value which expresses the selected target. Must be 0 for NEON or 1 for OpenCL or 2 (OpenCL with Tuner)
324 *
325 * @return the TargetHint
326 */
327inline graph2::Target set_target_hint2(int target)
328{
Georgios Pinitasfbb80542018-03-27 17:15:49 +0100329 ARM_COMPUTE_ERROR_ON_MSG(target > 3, "Invalid target. Target must be 0 (NEON), 1 (OpenCL), 2 (OpenCL + Tuner), 3 (GLES)");
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000330 if((target == 1 || target == 2) && arm_compute::opencl_is_available())
331 {
332 // If type of target is OpenCL, check if OpenCL is available and initialize the scheduler
333 return graph2::Target::CL;
334 }
Georgios Pinitasfbb80542018-03-27 17:15:49 +0100335 else if(target == 3)
336 {
337 return graph2::Target::GC;
338 }
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000339 else
340 {
341 return graph2::Target::NEON;
342 }
343}
Michalis Spyroue4720822017-10-02 17:44:52 +0100344} // namespace graph_utils
Anthony Barbier2a07e182017-08-04 18:20:27 +0100345} // namespace arm_compute
346
347#endif /* __ARM_COMPUTE_GRAPH_UTILS_H__ */