6.3. Python Programming Details

SophonSDK provides a Python programming interface to users through the SAIL library.

SAIL (Sophon Artificial Intelligent Library) is the core module of Sophon Inference. SAIL encapsulated BMLib, BMDecoder, BMCV and BMRuntime in SophonSDK. SophonSDK original “load bmodel and drive TPU reasoning”, “drive TPU+VPP to do image processing”, “drive VPU to do image and video decoding” and other functions abstract into a more simple C++ interface to provide external; It is repackaged using pybind11 to provide a concise and easy-to-use python interface.

This section introduces python interface programming by using the YOLOV5 detection algorithm as an example.

注解

Sample code path:sophon-demo/sample/YOLOV5

At present, all classes, enumerations and functions in SAIL module are in the “sail” namespace. The core classes include:

  • Handle: bm_handle_t wrapper class of BMLib in SDK, device handle, and context information used to interact with the kernel driver.

  • Tensor: A wrapper class for BMLib from the SDK that encapsulates device memory management and system memory synchronization.

  • Engine: Wrapper class of BMRuntime in SDK, which can load bmodel and drive TPU for inference. An Engine instance can load an arbitrary bmodel, automatically managing the memory corresponding to the input tensor and the output tensor.

  • Decoder: Use VPU to decode video, JPU to decode image, both are hardware decoding.

  • Bmcv: Packaging class of BMCV in SDK, which encapsulates a series of image processing functions and can drive TPU for image processing.

For more information about the interface, please read the SAIL User Development Manual .

This chapter mainly introduces the following three aspects:

  • Loading model

  • Preprocessing

  • Inference

6.3.1. Loading model

1import sophon.sail as sail
2
3...
4
5engine = sail.Engine(model_path, device_id, io_mode)
6
7...

6.3.2. Preprocessing

 1class PreProcess:
 2    def __init__(self, width, height, batch_size, img_dtype, input_scale=None):
 3
 4        self.std = np.array([255., 255., 255.], dtype=np.float32)
 5        self.batch_size = batch_size
 6        self.input_scale = float(1.0) if input_scale is None else input_scale
 7        self.img_dtype = img_dtype
 8
 9        self.width = width
10        self.height = height
11        self.use_resize_padding = True
12        self.use_vpp = False
13        ...
14
15    def resize(self, img, handle, bmcv):
16
17        if self.use_resize_padding:
18            img_w = img.width()
19            img_h = img.height()
20            r_w = self.width / img_w
21            r_h = self.height / img_h
22
23            if r_h > r_w:
24                tw = self.width
25                th = int(r_w * img_h)
26                tx1 = tx2 = 0
27                ty1 = int((self.height - th) / 2)
28                ty2 = self.height - th - ty1
29
30            else:
31                tw = int(r_h * img_w)
32                th = self.height
33                tx1 = int((self.width - tw) / 2)
34                tx2 = self.width - tw - tx1
35                ty1 = ty2 = 0
36
37            ratio = (min(r_w, r_h), min(r_w, r_h))
38            txy = (tx1, ty1)
39            attr = sail.PaddingAtrr()
40            attr.set_stx(tx1)
41            attr.set_sty(ty1)
42            attr.set_w(tw)
43            attr.set_h(th)
44            attr.set_r(114)
45            attr.set_g(114)
46            attr.set_b(114)
47
48            tmp_planar_img = sail.BMImage(handle, img.height(), img.width(),
49                                      sail.Format.FORMAT_RGB_PLANAR, sail.DATA_TYPE_EXT_1N_BYTE)
50            bmcv.convert_format(img, tmp_planar_img)
51            preprocess_fn = bmcv.vpp_crop_and_resize_padding if self.use_vpp else bmcv.crop_and_resize_padding
52            resized_img_rgb = preprocess_fn(tmp_planar_img,
53                                        0, 0, img.width(), img.height(),
54                                        self.width, self.height, attr)
55        else:
56            r_w = self.width / img.width()
57            r_h = self.height / img.height()
58            ratio = (r_w, r_h)
59            txy = (0, 0)
60            tmp_planar_img = sail.BMImage(handle, img.height(), img.width(),
61                                        sail.Format.FORMAT_RGB_PLANAR, sail.DATA_TYPE_EXT_1N_BYTE)
62            bmcv.convert_format(img, tmp_planar_img)
63            preprocess_fn = bmcv.vpp_resize if self.use_vpp else bmcv.resize
64            resized_img_rgb = preprocess_fn(tmp_planar_img, self.width, self.height)
65        return resized_img_rgb, ratio, txy
66
67    ...
68
69    def norm_batch(self, resized_images, handle, bmcv):
70
71        bm_array = eval('sail.BMImageArray{}D'.format(self.batch_size))
72
73        preprocessed_imgs = bm_array(handle,
74                                 self.height,
75                                 self.width,
76                                 sail.FORMAT_RGB_PLANAR,
77                                 self.img_dtype)
78
79        a = 1 / self.std
80        b = (0, 0, 0)
81        alpha_beta = tuple([(ia * self.input_scale, ib * self.input_scale) for ia, ib in zip(a, b)])
82
83        # do convert_to
84        bmcv.convert_to(resized_images, preprocessed_imgs, alpha_beta)
85        return preprocessed_imgs

6.3.3. Inference

 1class SophonInference:
 2    def __init__(self, **kwargs):
 3
 4        ...
 5
 6        self.io_mode = sail.IOMode.SYSIO
 7        self.engine = sail.Engine(self.model_path, self.device_id, self.io_mode)
 8        self.handle = self.engine.get_handle()
 9        self.graph_name = self.engine.get_graph_names()[0]
10        self.bmcv = sail.Bmcv(self.handle)
11
12        ...
13
14        input_names = self.engine.get_input_names(self.graph_name)
15        for input_name in input_names:
16
17            input_shape = self.engine.get_input_shape(self.graph_name, input_name)
18            input_dtype = self.engine.get_input_dtype(self.graph_name, input_name)
19            input_scale = self.engine.get_input_scale(self.graph_name, input_name)
20            ...
21            if self.input_mode:
22                input = sail.Tensor(self.handle, input_shape, input_dtype, True, True)
23            ...
24            input_tensors[input_name] = input
25            ...
26
27        output_names = self.engine.get_output_names(self.graph_name)
28
29        for output_name in output_names:
30
31            output_shape = self.engine.get_output_shape(self.graph_name, output_name)
32            output_dtype = self.engine.get_output_dtype(self.graph_name, output_name)
33            output_scale = self.engine.get_output_scale(self.graph_name, output_name)
34            ...
35            if self.input_mode:
36                output = sail.Tensor(self.handle, output_shape, output_dtype, True, True)
37            ...
38            output_tensors[output_name] = output
39            ...
40    def infer_bmimage(self, input_data):
41        self.get_input_feed(self.input_names, input_data)
42
43        #inference
44        self.engine.process(self.graph_name, self.input_tensors, self.output_tensors)
45        outputs_dict = OrderedDict()
46        for name in self.output_names:
47            outputs_dict[name] = self.output_tensors[name].asnumpy().copy() * self.output_scales[name]
48        return outputs_dict