3 Copyright (C) 2018-2020 Intel Corporation
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
9 http://www.apache.org/licenses/LICENSE-2.0
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
20 from argparse import ArgumentParser, SUPPRESS
24 from openvino.inference_engine import IECore, IENetwork
26 from ngraph.impl import Function
27 from functools import reduce
31 def build_argparser() -> ArgumentParser:
32 parser = ArgumentParser(add_help=False)
33 args = parser.add_argument_group('Options')
34 args.add_argument('-h', '--help', action='help', default=SUPPRESS, help='Show this help message and exit.')
35 args.add_argument('-i', '--input', help='Required. Path to a folder with images or path to an image files',
36 required=True, type=str, nargs="+")
37 args.add_argument('-m', '--model', help='Required. Path to file where weights for the network are located')
38 args.add_argument('-d', '--device',
39 help='Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL, MYRIAD or HETERO: '
40 'is acceptable. The sample will look for a suitable plugin for device specified. Default '
42 default='CPU', type=str)
43 args.add_argument('--labels', help='Optional. Path to a labels mapping file', default=None, type=str)
44 args.add_argument('-nt', '--number_top', help='Optional. Number of top results', default=1, type=int)
49 def list_input_images(input_dirs: list):
51 for input_dir in input_dirs:
52 if os.path.isdir(input_dir):
53 for root, directories, filenames in os.walk(input_dir):
54 for filename in filenames:
55 images.append(os.path.join(root, filename))
56 elif os.path.isfile(input_dir):
57 images.append(input_dir)
62 def read_image(image_path: np):
63 # try to read image in usual image formats
64 image = cv2.imread(image_path, cv2.IMREAD_UNCHANGED)
66 # try to open image as ubyte
68 with open(image_path, 'rb') as f:
69 image_file = open(image_path, 'rb')
71 st.unpack('>4B', image_file.read(4)) # need to skip 4 bytes
72 nimg = st.unpack('>I', image_file.read(4))[0] # number of images
73 nrow = st.unpack('>I', image_file.read(4))[0] # number of rows
74 ncolumn = st.unpack('>I', image_file.read(4))[0] # number of column
75 nbytes = nimg * nrow * ncolumn * 1 # each pixel data is 1 byte
77 assert nimg == 1, log.error('Sample supports ubyte files with 1 image inside')
79 image = np.asarray(st.unpack('>' + 'B' * nbytes, image_file.read(nbytes))).reshape(
85 def shape_and_length(shape: list):
86 length = reduce(lambda x, y: x*y, shape)
90 def create_ngraph_function(args) -> Function:
91 weights = np.fromfile(args.model, dtype=np.float32)
93 padding_begin = [0, 0]
97 input_shape = [64, 1, 28, 28]
98 param_node = ngraph.parameter(input_shape, np.float32, 'Parameter')
101 conv_1_kernel_shape, conv_1_kernel_length = shape_and_length([20, 1, 5, 5])
102 conv_1_kernel = ngraph.constant(weights[0:conv_1_kernel_length].reshape(conv_1_kernel_shape))
103 weights_offset += conv_1_kernel_length
104 conv_1_node = ngraph.convolution(param_node, conv_1_kernel, [1, 1], padding_begin, padding_end, [1, 1])
107 add_1_kernel_shape, add_1_kernel_length = shape_and_length([1, 20, 1, 1])
108 add_1_kernel = ngraph.constant(
109 weights[weights_offset:weights_offset + add_1_kernel_length].reshape(add_1_kernel_shape)
111 weights_offset += add_1_kernel_length
112 add_1_node = ngraph.add(conv_1_node, add_1_kernel)
115 maxpool_1_node = ngraph.max_pool(add_1_node, [2, 2], padding_begin, padding_end, [2, 2], 'ceil', None)
118 conv_2_kernel_shape, conv_2_kernel_length = shape_and_length([50, 20, 5, 5])
119 conv_2_kernel = ngraph.constant(
120 weights[weights_offset:weights_offset + conv_2_kernel_length].reshape(conv_2_kernel_shape)
122 weights_offset += conv_2_kernel_length
123 conv_2_node = ngraph.convolution(maxpool_1_node, conv_2_kernel, [1, 1], padding_begin, padding_end, [1, 1])
126 add_2_kernel_shape, add_2_kernel_length = shape_and_length([1, 50, 1, 1])
127 add_2_kernel = ngraph.constant(
128 weights[weights_offset:weights_offset + add_2_kernel_length].reshape(add_2_kernel_shape)
130 weights_offset += add_2_kernel_length
131 add_2_node = ngraph.add(conv_2_node, add_2_kernel)
134 maxpool_2_node = ngraph.max_pool(add_2_node, [2, 2], padding_begin, padding_end, [2, 2], 'ceil', None)
137 reshape_1_dims, reshape_1_length = shape_and_length([2])
138 # workaround to get int64 weights from float32 ndarray w/o unnecessary copying
139 dtype_weights = np.frombuffer(
140 weights[weights_offset:weights_offset + 2*reshape_1_length], dtype=np.int64
142 reshape_1_kernel = ngraph.constant(dtype_weights)
143 weights_offset += 2*reshape_1_length
144 reshape_1_node = ngraph.reshape(maxpool_2_node, reshape_1_kernel, True)
147 matmul_1_kernel_shape, matmul_1_kernel_length = shape_and_length([500, 800])
148 matmul_1_kernel = ngraph.constant(
149 weights[weights_offset:weights_offset + matmul_1_kernel_length].reshape(matmul_1_kernel_shape)
151 weights_offset += matmul_1_kernel_length
152 matmul_1_node = ngraph.matmul(reshape_1_node, matmul_1_kernel, False, True)
155 add_3_kernel_shape, add_3_kernel_length = shape_and_length([1, 500])
156 add_3_kernel = ngraph.constant(
157 weights[weights_offset:weights_offset + add_3_kernel_length].reshape(add_3_kernel_shape)
159 weights_offset += add_3_kernel_length
160 add_3_node = ngraph.add(matmul_1_node, add_3_kernel)
163 relu_node = ngraph.relu(add_3_node)
166 reshape_2_kernel = ngraph.constant(dtype_weights)
167 reshape_2_node = ngraph.reshape(relu_node, reshape_2_kernel, True)
170 matmul_2_kernel_shape, matmul_2_kernel_length = shape_and_length([10, 500])
171 matmul_2_kernel = ngraph.constant(
172 weights[weights_offset:weights_offset + matmul_2_kernel_length].reshape(matmul_2_kernel_shape)
174 weights_offset += matmul_2_kernel_length
175 matmul_2_node = ngraph.matmul(reshape_2_node, matmul_2_kernel, False, True)
178 add_4_kernel_shape, add_4_kernel_length = shape_and_length([1, 10])
179 add_4_kernel = ngraph.constant(
180 weights[weights_offset:weights_offset + add_4_kernel_length].reshape(add_4_kernel_shape)
182 weights_offset += add_4_kernel_length
183 add_4_node = ngraph.add(matmul_2_node, add_4_kernel)
187 softmax_node = ngraph.softmax(add_4_node, softmax_axis)
190 result_node = ngraph.result(softmax_node)
193 function = Function(result_node, [param_node], 'lenet')
199 log.basicConfig(format='[ %(levelname)s ] %(message)s', level=log.INFO, stream=sys.stdout)
200 args = build_argparser().parse_args()
202 input_images = list_input_images(args.input)
204 # Loading network using ngraph function
205 ngraph_function = create_ngraph_function(args)
206 net = IENetwork(Function.to_capsule(ngraph_function))
208 assert len(net.input_info.keys()) == 1, "Sample supports only single input topologies"
209 assert len(net.outputs) == 1, "Sample supports only single output topologies"
211 log.info("Preparing input blobs")
212 input_blob = next(iter(net.input_info))
213 out_blob = next(iter(net.outputs))
214 net.batch_size = len(input_images)
216 # Read and pre-process input images
217 n, c, h, w = net.input_info[input_blob].input_data.shape
218 images = np.ndarray(shape=(n, c, h, w))
220 image = read_image(input_images[i])
221 assert image is not None, log.error("Can't open an image {}".format(input_images[i]))
222 assert len(image.shape) == 2, log.error('Sample supports images with 1 channel only')
223 if image.shape[:] != (w, h):
224 log.warning("Image {} is resized from {} to {}".format(input_images[i], image.shape[:], (w, h)))
225 image = cv2.resize(image, (w, h))
227 log.info("Batch size is {}".format(n))
229 log.info("Creating Inference Engine")
232 log.info('Loading model to the device')
233 exec_net = ie.load_network(network=net, device_name=args.device.upper())
235 # Start sync inference
236 log.info('Creating infer request and starting inference')
237 res = exec_net.infer(inputs={input_blob: images})
240 log.info("Processing output blob")
242 log.info("Top {} results: ".format(args.number_top))
244 # Read labels file if it is provided as argument
247 with open(args.labels, 'r') as f:
248 labels_map = [x.split(sep=' ', maxsplit=1)[-1].strip() for x in f]
250 classid_str = "classid"
251 probability_str = "probability"
252 for i, probs in enumerate(res):
253 probs = np.squeeze(probs)
254 top_ind = np.argsort(probs)[-args.number_top:][::-1]
255 print("Image {}\n".format(input_images[i]))
256 print(classid_str, probability_str)
257 print("{} {}".format('-' * len(classid_str), '-' * len(probability_str)))
258 for class_id in top_ind:
259 det_label = labels_map[class_id] if labels_map else "{}".format(class_id)
260 label_length = len(det_label)
261 space_num_before = (len(classid_str) - label_length) // 2
262 space_num_after = len(classid_str) - (space_num_before + label_length) + 2
263 space_num_before_prob = (len(probability_str) - len(str(probs[class_id]))) // 2
264 print("{}{}{}{}{:.7f}".format(' ' * space_num_before, det_label,
265 ' ' * space_num_after, ' ' * space_num_before_prob,
269 log.info('This sample is an API example, for any performance measurements '
270 'please use the dedicated benchmark_app tool')
273 if __name__ == '__main__':
274 sys.exit(main() or 0)