blob: 046c7779b1ccb28b2b7c3fe0d1817862d305ac23 [file] [log] [blame]
Giorgio Arenaa66eaa22017-12-21 19:50:06 +00001/*
2 * Copyright (c) 2017-2018 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/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
30using namespace arm_compute;
31using namespace arm_compute::graph;
32using namespace arm_compute::graph_utils;
33
34/** Example demonstrating how to implement QASYMM8 MobileNet's network using the Compute Library's graph API
35 *
36 * @param[in] argc Number of arguments
37 * @param[in] argv Arguments ( [optional] Path to the weights folder, [optional] npy_input, [optional] labels )
38 */
39class GraphMobileNetQASYMM8Example : public utils::Example
40{
41public:
42 void do_setup(int argc, char **argv) override
43 {
44 std::string data_path; /* Path to the trainable data */
45 std::string input; /* Image data */
46 std::string label; /* Label data */
47
48 // Quantization info taken from the AndroidNN QASYMM8 MobileNet example
49 const QuantizationInfo in_quant_info = QuantizationInfo(0.0078125f, 128);
50 const QuantizationInfo mid_quant_info = QuantizationInfo(0.0784313753247f, 128);
51
52 const std::vector<QuantizationInfo> conv_weights_quant_info =
53 {
54 QuantizationInfo(0.031778190285f, 156), // conv0
55 QuantizationInfo(0.00604454148561f, 66) // conv14
56 };
57
58 const std::vector<QuantizationInfo> depth_weights_quant_info =
59 {
60 QuantizationInfo(0.254282623529f, 129), // dwsc1
61 QuantizationInfo(0.12828284502f, 172), // dwsc2
62 QuantizationInfo(0.265911251307f, 83), // dwsc3
63 QuantizationInfo(0.0985597148538f, 30), // dwsc4
64 QuantizationInfo(0.0631204470992f, 54), // dwsc5
65 QuantizationInfo(0.0137207424268f, 141), // dwsc6
66 QuantizationInfo(0.0817828401923f, 125), // dwsc7
67 QuantizationInfo(0.0393880493939f, 164), // dwsc8
68 QuantizationInfo(0.211694166064f, 129), // dwsc9
69 QuantizationInfo(0.158015936613f, 103), // dwsc10
70 QuantizationInfo(0.0182712618262f, 137), // dwsc11
71 QuantizationInfo(0.0127998134121f, 134), // dwsc12
72 QuantizationInfo(0.299285322428f, 161) // dwsc13
73 };
74
75 const std::vector<QuantizationInfo> point_weights_quant_info =
76 {
77 QuantizationInfo(0.0425766184926f, 129), // dwsc1
78 QuantizationInfo(0.0250773020089f, 94), // dwsc2
79 QuantizationInfo(0.015851572156f, 93), // dwsc3
80 QuantizationInfo(0.0167811904103f, 98), // dwsc4
81 QuantizationInfo(0.00951790809631f, 135), // dwsc5
82 QuantizationInfo(0.00999817531556f, 128), // dwsc6
83 QuantizationInfo(0.00590536883101f, 126), // dwsc7
84 QuantizationInfo(0.00576109671965f, 133), // dwsc8
85 QuantizationInfo(0.00830461271107f, 142), // dwsc9
86 QuantizationInfo(0.0152327232063f, 72), // dwsc10
87 QuantizationInfo(0.00741417845711f, 125), // dwsc11
88 QuantizationInfo(0.0135628981516f, 142), // dwsc12
89 QuantizationInfo(0.0338749065995f, 140) // dwsc13
90 };
91
92 // Parse arguments
93 if(argc < 2)
94 {
95 // Print help
96 std::cout << "Usage: " << argv[0] << " [path_to_data] [npy_input] [labels]\n\n";
97 std::cout << "No data folder provided: using random values\n\n";
98 }
99 else if(argc == 2)
100 {
101 data_path = argv[1];
102 std::cout << "Usage: " << argv[0] << " " << argv[1] << " [npy_input] [labels]\n\n";
103 std::cout << "No input provided: using random values\n\n";
104 }
105 else if(argc == 3)
106 {
107 data_path = argv[1];
108 input = argv[2];
109 std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [labels]\n\n";
110 std::cout << "No text file with labels provided: skipping output accessor\n\n";
111 }
112 else
113 {
114 data_path = argv[1];
115 input = argv[2];
116 label = argv[3];
117 }
118
119 graph << TargetHint::OPENCL
120 << arm_compute::graph::Tensor(TensorInfo(TensorShape(224U, 224U, 3U, 1U), 1, DataType::QASYMM8, in_quant_info),
121 get_weights_accessor(data_path, "/cnn_data/mobilenet_qasymm8_model/" + input))
122 << ConvolutionLayer(
123 3U, 3U, 32U,
124 get_weights_accessor(data_path, "/cnn_data/mobilenet_qasymm8_model/Conv2d_0_weights.npy"),
125 get_weights_accessor(data_path, "/cnn_data/mobilenet_qasymm8_model/Conv2d_0_bias.npy"),
126 PadStrideInfo(2U, 2U, 0U, 1U, 0U, 1U, DimensionRoundingType::FLOOR),
127 1, WeightsInfo(),
128 conv_weights_quant_info.at(0),
129 mid_quant_info)
130 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.f))
131 << get_dwsc_node(data_path, "Conv2d_1", 64U, PadStrideInfo(1U, 1U, 1U, 1U), PadStrideInfo(1U, 1U, 0U, 0U), depth_weights_quant_info.at(0), point_weights_quant_info.at(0))
132 << get_dwsc_node(data_path, "Conv2d_2", 128U, PadStrideInfo(2U, 2U, 0U, 1U, 0U, 1U, DimensionRoundingType::FLOOR), PadStrideInfo(1U, 1U, 0U, 0U), depth_weights_quant_info.at(1),
133 point_weights_quant_info.at(1))
134 << get_dwsc_node(data_path, "Conv2d_3", 128U, PadStrideInfo(1U, 1U, 1U, 1U, 1U, 1U, DimensionRoundingType::FLOOR), PadStrideInfo(1U, 1U, 0U, 0U), depth_weights_quant_info.at(2),
135 point_weights_quant_info.at(2))
136 << get_dwsc_node(data_path, "Conv2d_4", 256U, PadStrideInfo(2U, 2U, 0U, 1U, 0U, 1U, DimensionRoundingType::FLOOR), PadStrideInfo(1U, 1U, 0U, 0U), depth_weights_quant_info.at(3),
137 point_weights_quant_info.at(3))
138 << get_dwsc_node(data_path, "Conv2d_5", 256U, PadStrideInfo(1U, 1U, 1U, 1U, 1U, 1U, DimensionRoundingType::FLOOR), PadStrideInfo(1U, 1U, 0U, 0U), depth_weights_quant_info.at(4),
139 point_weights_quant_info.at(4))
140 << get_dwsc_node(data_path, "Conv2d_6", 512U, PadStrideInfo(2U, 2U, 0U, 1U, 0U, 1U, DimensionRoundingType::FLOOR), PadStrideInfo(1U, 1U, 0U, 0U), depth_weights_quant_info.at(5),
141 point_weights_quant_info.at(5))
142 << get_dwsc_node(data_path, "Conv2d_7", 512U, PadStrideInfo(1U, 1U, 1U, 1U, 1U, 1U, DimensionRoundingType::FLOOR), PadStrideInfo(1U, 1U, 0U, 0U), depth_weights_quant_info.at(6),
143 point_weights_quant_info.at(6))
144 << get_dwsc_node(data_path, "Conv2d_8", 512U, PadStrideInfo(1U, 1U, 1U, 1U, 1U, 1U, DimensionRoundingType::FLOOR), PadStrideInfo(1U, 1U, 0U, 0U), depth_weights_quant_info.at(7),
145 point_weights_quant_info.at(7))
146 << get_dwsc_node(data_path, "Conv2d_9", 512U, PadStrideInfo(1U, 1U, 1U, 1U, 1U, 1U, DimensionRoundingType::FLOOR), PadStrideInfo(1U, 1U, 0U, 0U), depth_weights_quant_info.at(8),
147 point_weights_quant_info.at(8))
148 << get_dwsc_node(data_path, "Conv2d_10", 512U, PadStrideInfo(1U, 1U, 1U, 1U, 1U, 1U, DimensionRoundingType::FLOOR), PadStrideInfo(1U, 1U, 0U, 0U), depth_weights_quant_info.at(9),
149 point_weights_quant_info.at(9))
150 << get_dwsc_node(data_path, "Conv2d_11", 512U, PadStrideInfo(1U, 1U, 1U, 1U, 1U, 1U, DimensionRoundingType::FLOOR), PadStrideInfo(1U, 1U, 0U, 0U), depth_weights_quant_info.at(10),
151 point_weights_quant_info.at(10))
152 << get_dwsc_node(data_path, "Conv2d_12", 1024U, PadStrideInfo(2U, 2U, 0U, 1U, 0U, 1U, DimensionRoundingType::FLOOR), PadStrideInfo(1U, 1U, 0U, 0U), depth_weights_quant_info.at(11),
153 point_weights_quant_info.at(11))
154 << get_dwsc_node(data_path, "Conv2d_13", 1024U, PadStrideInfo(1U, 1U, 1U, 1U, 1U, 1U, DimensionRoundingType::FLOOR), PadStrideInfo(1U, 1U, 0U, 0U), depth_weights_quant_info.at(12),
155 point_weights_quant_info.at(12))
156 << PoolingLayer(PoolingLayerInfo(PoolingType::AVG))
157 << ConvolutionLayer(
158 1U, 1U, 1001U,
159 get_weights_accessor(data_path, "/cnn_data/mobilenet_qasymm8_model/Logits_Conv2d_1c_1x1_weights.npy"),
160 get_weights_accessor(data_path, "/cnn_data/mobilenet_qasymm8_model/Logits_Conv2d_1c_1x1_bias.npy"),
161 PadStrideInfo(1U, 1U, 0U, 0U), 1, WeightsInfo(), conv_weights_quant_info.at(1))
162 << ReshapeLayer(TensorShape(1001U))
163 << SoftmaxLayer()
164 << arm_compute::graph::Tensor(get_output_accessor(label, 5));
165 }
166 void do_run() override
167 {
168 // Run graph
169 graph.run();
170 }
171
172private:
173 Graph graph{};
174
175 /** This function produces a depthwise separable convolution node (i.e. depthwise + pointwise layers) with ReLU6 activation after each layer.
176 *
177 * @param[in] data_path Path to trainable data folder
178 * @param[in] param_path Prefix of specific set of weights/biases data
179 * @param[in] conv_filt Filters depths for pointwise convolution
180 * @param[in] dwc_pad_stride_info PadStrideInfo for depthwise convolution
181 * @param[in] conv_pad_stride_info PadStrideInfo for pointwise convolution
182 * @param[in] depth_weights_quant_info QuantizationInfo for depthwise convolution's weights
183 * @param[in] point_weights_quant_info QuantizationInfo for pointwise convolution's weights
184 *
185 * @return The complete dwsc node
186 */
187 BranchLayer get_dwsc_node(const std::string &data_path, std::string &&param_path,
188 const unsigned int conv_filt,
189 PadStrideInfo dwc_pad_stride_info, PadStrideInfo conv_pad_stride_info,
190 QuantizationInfo depth_weights_quant_info, QuantizationInfo point_weights_quant_info)
191 {
192 std::string total_path = "/cnn_data/mobilenet_qasymm8_model/" + param_path + "_";
193 SubGraph sg;
194
195 sg << DepthwiseConvolutionLayer(
196 3U, 3U,
197 get_weights_accessor(data_path, total_path + "depthwise_weights.npy"),
198 get_weights_accessor(data_path, total_path + "depthwise_bias.npy"),
199 dwc_pad_stride_info,
200 true,
201 depth_weights_quant_info)
202 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.f))
203 << ConvolutionLayer(
204 1U, 1U, conv_filt,
205 get_weights_accessor(data_path, total_path + "pointwise_weights.npy"),
206 get_weights_accessor(data_path, total_path + "pointwise_bias.npy"),
207 conv_pad_stride_info,
208 1, WeightsInfo(),
209 point_weights_quant_info)
210 << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.f));
211
212 return BranchLayer(std::move(sg));
213 }
214};
215/** Main program for MobileNetQASYMM8
216 *
217 * @param[in] argc Number of arguments
218 * @param[in] argv Arguments ( [optional] Path to the weights folder, [optional] npy_input, [optional] labels )
219 */
220int main(int argc, char **argv)
221{
222 return utils::run_example<GraphMobileNetQASYMM8Example>(argc, argv);
223}