blob: c8cc5b25583032beabcfc161a28b0e691c521832 [file] [log] [blame]
Anthony Barbier8140e1e2017-12-14 23:48:46 +00001/*
Anthony Barbier06ea0482018-02-22 15:45:35 +00002 * Copyright (c) 2017-2018 ARM Limited.
Anthony Barbier8140e1e2017-12-14 23:48:46 +00003 *
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/graph/Graph.h"
25#include "arm_compute/graph/Nodes.h"
26#include "support/ToolchainSupport.h"
27#include "utils/GraphUtils.h"
28#include "utils/Utils.h"
29
30#include <cstdlib>
31
Anthony Barbierf45d5a92018-01-24 16:23:15 +000032using namespace arm_compute::utils;
Anthony Barbier8140e1e2017-12-14 23:48:46 +000033using namespace arm_compute::graph;
34using namespace arm_compute::graph_utils;
35
Anthony Barbier06ea0482018-02-22 15:45:35 +000036namespace
37{
38/** This function checks if we can use GEMM-based convolution trying to allocate a memory of size "size_in_bytes"
39 *
40 * @param[in] size_in_bytes Memory size in bytes needed for VGG-16
41 *
42 * @return The convolution layer hint
43 */
44ConvolutionMethodHint convolution_hint_vgg16(size_t size_in_bytes)
45{
46 return ((get_mem_free_from_meminfo() * 1024) >= size_in_bytes) ? ConvolutionMethodHint::GEMM : ConvolutionMethodHint::DIRECT;
47}
48} // namespace
49
Anthony Barbier8140e1e2017-12-14 23:48:46 +000050/** Example demonstrating how to implement VGG16's network using the Compute Library's graph API
51 *
52 * @param[in] argc Number of arguments
53 * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels )
54 */
Anthony Barbierf45d5a92018-01-24 16:23:15 +000055class GraphVGG16Example : public Example
Anthony Barbier8140e1e2017-12-14 23:48:46 +000056{
Anthony Barbierf45d5a92018-01-24 16:23:15 +000057public:
58 void do_setup(int argc, char **argv) override
59 {
60 std::string data_path; /* Path to the trainable data */
61 std::string image; /* Image data */
62 std::string label; /* Label data */
Anthony Barbier8140e1e2017-12-14 23:48:46 +000063
Anthony Barbier06ea0482018-02-22 15:45:35 +000064 // Create a preprocessor object
65 const std::array<float, 3> mean_rgb{ { 123.68f, 116.779f, 103.939f } };
66 std::unique_ptr<IPreprocessor> preprocessor = arm_compute::support::cpp14::make_unique<CaffePreproccessor>(mean_rgb);
Anthony Barbier8140e1e2017-12-14 23:48:46 +000067
Anthony Barbier06ea0482018-02-22 15:45:35 +000068 // Set target. 0 (NEON), 1 (OpenCL), 2 (OpenCL with Tuner). By default it is NEON
69 const int int_target_hint = argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0;
70 TargetHint target_hint = set_target_hint(int_target_hint);
71
72 // Check if we can use GEMM-based convolutions evaluating if the platform has at least 1.8 GB of available memory
73 const size_t memory_required = 1932735283L;
74 ConvolutionMethodHint convolution_hint = convolution_hint_vgg16(memory_required);
Anthony Barbier8140e1e2017-12-14 23:48:46 +000075
Anthony Barbierf45d5a92018-01-24 16:23:15 +000076 // Parse arguments
77 if(argc < 2)
78 {
79 // Print help
80 std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels]\n\n";
81 std::cout << "No data folder provided: using random values\n\n";
82 }
83 else if(argc == 2)
84 {
85 std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels]\n\n";
86 std::cout << "No data folder provided: using random values\n\n";
87 }
88 else if(argc == 3)
89 {
90 data_path = argv[2];
91 std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels]\n\n";
92 std::cout << "No image provided: using random values\n\n";
93 }
94 else if(argc == 4)
95 {
96 data_path = argv[2];
97 image = argv[3];
98 std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels]\n\n";
99 std::cout << "No text file with labels provided: skipping output accessor\n\n";
100 }
101 else
102 {
103 data_path = argv[2];
104 image = argv[3];
105 label = argv[4];
106 }
107
108 graph << target_hint
109 << convolution_hint
110 << Tensor(TensorInfo(TensorShape(224U, 224U, 3U, 1U), 1, DataType::F32),
Anthony Barbier06ea0482018-02-22 15:45:35 +0000111 get_input_accessor(image, std::move(preprocessor)))
Anthony Barbierf45d5a92018-01-24 16:23:15 +0000112 // Layer 1
113 << ConvolutionLayer(
114 3U, 3U, 64U,
115 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv1_1_w.npy"),
116 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv1_1_b.npy"),
117 PadStrideInfo(1, 1, 1, 1))
118 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
119 // Layer 2
120 << ConvolutionLayer(
121 3U, 3U, 64U,
122 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv1_2_w.npy"),
123 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv1_2_b.npy"),
124 PadStrideInfo(1, 1, 1, 1))
125 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
126 << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0)))
127 // Layer 3
128 << ConvolutionLayer(
129 3U, 3U, 128U,
130 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv2_1_w.npy"),
131 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv2_1_b.npy"),
132 PadStrideInfo(1, 1, 1, 1))
133 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
134 // Layer 4
135 << ConvolutionLayer(
136 3U, 3U, 128U,
137 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv2_2_w.npy"),
138 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv2_2_b.npy"),
139 PadStrideInfo(1, 1, 1, 1))
140 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
141 << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0)))
142 // Layer 5
143 << ConvolutionLayer(
144 3U, 3U, 256U,
145 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_1_w.npy"),
146 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_1_b.npy"),
147 PadStrideInfo(1, 1, 1, 1))
148 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
149 // Layer 6
150 << ConvolutionLayer(
151 3U, 3U, 256U,
152 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_2_w.npy"),
153 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_2_b.npy"),
154 PadStrideInfo(1, 1, 1, 1))
155 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
156 // Layer 7
157 << ConvolutionLayer(
158 3U, 3U, 256U,
159 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_3_w.npy"),
160 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_3_b.npy"),
161 PadStrideInfo(1, 1, 1, 1))
162 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
163 << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0)))
164 // Layer 8
165 << ConvolutionLayer(
166 3U, 3U, 512U,
167 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_1_w.npy"),
168 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_1_b.npy"),
169 PadStrideInfo(1, 1, 1, 1))
170 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
171 // Layer 9
172 << ConvolutionLayer(
173 3U, 3U, 512U,
174 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_2_w.npy"),
175 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_2_b.npy"),
176 PadStrideInfo(1, 1, 1, 1))
177 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
178 // Layer 10
179 << ConvolutionLayer(
180 3U, 3U, 512U,
181 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_3_w.npy"),
182 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_3_b.npy"),
183 PadStrideInfo(1, 1, 1, 1))
184 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
185 << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0)))
186 // Layer 11
187 << ConvolutionLayer(
188 3U, 3U, 512U,
189 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_1_w.npy"),
190 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_1_b.npy"),
191 PadStrideInfo(1, 1, 1, 1))
192 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
193 // Layer 12
194 << ConvolutionLayer(
195 3U, 3U, 512U,
196 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_2_w.npy"),
197 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_2_b.npy"),
198 PadStrideInfo(1, 1, 1, 1))
199 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
200 // Layer 13
201 << ConvolutionLayer(
202 3U, 3U, 512U,
203 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_3_w.npy"),
204 get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_3_b.npy"),
205 PadStrideInfo(1, 1, 1, 1))
206 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
207 << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0)))
208 // Layer 14
209 << FullyConnectedLayer(
210 4096U,
211 get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc6_w.npy"),
212 get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc6_b.npy"))
213 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
214 // Layer 15
215 << FullyConnectedLayer(
216 4096U,
217 get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc7_w.npy"),
218 get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc7_b.npy"))
219 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
220 // Layer 16
221 << FullyConnectedLayer(
222 1000U,
223 get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc8_w.npy"),
224 get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc8_b.npy"))
225 // Softmax
226 << SoftmaxLayer()
227 << Tensor(get_output_accessor(label, 5));
Anthony Barbier06ea0482018-02-22 15:45:35 +0000228
229 // In order to enable the OpenCL tuner, graph_init() has to be called only when all nodes have been instantiated
230 graph.graph_init(int_target_hint == 2);
Anthony Barbier8140e1e2017-12-14 23:48:46 +0000231 }
Anthony Barbierf45d5a92018-01-24 16:23:15 +0000232 void do_run() override
Anthony Barbier8140e1e2017-12-14 23:48:46 +0000233 {
Anthony Barbierf45d5a92018-01-24 16:23:15 +0000234 // Run graph
235 graph.run();
Anthony Barbier8140e1e2017-12-14 23:48:46 +0000236 }
237
Anthony Barbierf45d5a92018-01-24 16:23:15 +0000238private:
239 Graph graph{};
240};
Anthony Barbier8140e1e2017-12-14 23:48:46 +0000241
242/** Main program for VGG16
243 *
244 * @param[in] argc Number of arguments
245 * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels )
246 */
Anthony Barbierf45d5a92018-01-24 16:23:15 +0000247int main(int argc, char **argv)
Anthony Barbier8140e1e2017-12-14 23:48:46 +0000248{
Anthony Barbierf45d5a92018-01-24 16:23:15 +0000249 return arm_compute::utils::run_example<GraphVGG16Example>(argc, argv);
Anthony Barbier8140e1e2017-12-14 23:48:46 +0000250}