DLAP221上Yolov5s性能测试

1. 导出yolov5 ONNX模型

选择一台x64的PC机,OS为Ubuntu18.04,在此台机器上完成Yolov5模型转ONNX模型。

1.1 下载原始yolov5代码、模型和权重文件

  1. 下载yolov5源代码

    $ git clone -b v2.0 https://github.com/ultralytics/yolov5.git
    Cloning into 'yolov5'...
    remote: Enumerating objects: 6233, done.
    remote: Counting objects: 100% (27/27), done.
    remote: Compressing objects: 100% (20/20), done.
    remote: Total 6233 (delta 10), reused 14 (delta 7), pack-reused 6206
    Receiving objects: 100% (6233/6233), 8.45 MiB | 19.00 KiB/s, done.
    Resolving deltas: 100% (4268/4268), done.
    Note: checking out '2a149a48d65bf4d358d4289058ef6066cda8c7c9'.
    
    You are in 'detached HEAD' state. You can look around, make experimental
    changes and commit them, and you can discard any commits you make in this
    state without impacting any branches by performing another checkout.
    
    If you want to create a new branch to retain commits you create, you may
    do so (now or later) by using -b with the checkout command again. Example:
    
      git checkout -b <new-branch-name>
    
    
  2. 下载权重文件

    $ cd yolov5/weights
    
    $ wget https://github.com/ultralytics/yolov5/releases/download/v2.0/yolov5s.pt
    
    

    如果不能在设备上直接下载权重文件,请在别的平台下载权重文件,然后拷贝到设备上。

1.2 Pytorch模型转ONNX模型

  1. 修改models/export.py脚本生成onnx文件,注意目前onnx版本应选择11

    $ cd ~/yolov5/models
    $ vim export.py
    ... #省略部分
        # ONNX export
        try:
            import onnx
    
            print('\nStarting ONNX export with onnx %s...' % onnx.__version__)
            f = opt.weights.replace('.pt', '.onnx')  # filename
            model.fuse()  # only for ONNX
            ####修改此处的opset_version为11######
            torch.onnx.export(model, img, f, verbose=False, opset_version=11, input_names=['images'],
                              output_names=['classes', 'boxes'] if y is None else ['output'])
    
            # Checks
            onnx_model = onnx.load(f)  # load onnx model
            onnx.checker.check_model(onnx_model)  # check onnx model
            print(onnx.helper.printable_graph(onnx_model.graph))  # print a human readable model
            print('ONNX export success, saved as %s' % f)
        except Exception as e:
            print('ONNX export failure: %s' % e)
    ...#省略部分
    
    1. 安装docker,访问https://hub.docker.com/r/shinerchen/pytorch-1.8.1-py37-cpu下载docker 镜像

      $sudo apt-get install docker.io
      $sudo docker version
      Client:
       Version:           20.10.2
       API version:       1.41
       Go version:        go1.13.8
       Git commit:        20.10.2-0ubuntu1~18.04.2
       Built:             Tue Mar 30 21:24:16 2021
       OS/Arch:           linux/amd64
       Context:           default
       Experimental:      true
      
      Server:
       Engine:
        Version:          20.10.2
        API version:      1.41 (minimum version 1.12)
        Go version:       go1.13.8
        Git commit:       20.10.2-0ubuntu1~18.04.2
        Built:            Mon Mar 29 19:27:41 2021
        OS/Arch:          linux/amd64
        Experimental:     false
       containerd:
        Version:          1.3.3-0ubuntu1~18.04.4
        GitCommit:
       runc:
        Version:          spec: 1.0.2-dev
        GitCommit:
       docker-init:
        Version:          0.19.0
        GitCommit:
      
      $ sudo docker pull shinerchen/pytorch-1.8.1-py37-cpu
      $ sudo docker images
      REPOSITORY                                                        TAG           IMAGE ID       CREATED         SIZE
      shinerchen/pytorch-1.8.1-py37-cpu                                 latest        3f812182d768   2 hours ago     1.98GB
      
      
    2. 运行docker镜像,导出ONNX模型文件

      $ sudo docker run -it --ipc=host -v <你的yolov5的代码目录>:/data pytorch-1.8.1-py37-cpu:latest
      $ cd /data
      $ python3.7 models/export.py --weights ./weights/yolov5s.pt --img 640 --batch 1
      Namespace(batch_size=1, img_size=[640, 640], weights='./weights/yolov5s.pt')
      [W NNPACK.cpp:80] Could not initialize NNPACK! Reason: Unsupported hardware.
      
      Starting TorchScript export with torch 1.8.1+cpu...
      /usr/local/lib/python3.7/dist-packages/torch/jit/_trace.py:940: TracerWarning: Encountering a list at the output of the tracer might cause the trace to be incorrect, this is only valid if the container structure does not change based on the module's inputs. Consider using a constant container instead (e.g. for `list`, use a `tuple` instead. for `dict`, use a `NamedTuple` instead). If you absolutely need this and know the side effects, pass strict=False to trace() to allow this behavior.
        _force_outplace,
      TorchScript export success, saved as ./weights/yolov5s.torchscript.pt
      
      Starting ONNX export with onnx 1.9.0...
      ...
      ONNX export success, saved as ./weights/yolov5s.onnx
      
      Starting CoreML export with coremltools 4.1...
      WARNING:root:Tuple detected at graph output. This will be flattened in the converted model.
      Converting Frontend ==> MIL Ops: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████▋| 730/732 [00:00<00:00, 779.53 ops/s]
      Running MIL optimization passes: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████| 18/18 [00:00<00:00, 55.74 passes/s]
      Translating MIL ==> MLModel Ops: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████| 944/944 [00:01<00:00, 768.94 ops/s]
      CoreML export success, saved as ./weights/yolov5s.mlmodel
      
      Export complete. Visualize with https://github.com/lutzroeder/netron.
      
      
    3. 简化模型

      对导出的onnx模型使用onnx-simplifer工具进行简化

      $ pip3.7 install onnx-simplifier
      $ cd yolov5/weights
      $ python3.7 -m onnxsim --skip-optimization yolov5s.onnx yolov5s_sim.onnx
      Simplifying...
      Checking 0/3...
      Checking 1/3...
      Checking 2/3...
      Ok!
      

      创建包含以下代码的modify_yolov5.py脚本

      # Copyright 2020 Huawei Technologies Co., Ltd
      #
      # Licensed under the Apache License, Version 2.0 (the "License");
      # you may not use this file except in compliance with the License.
      # You may obtain a copy of the License at
      #
      #     http://www.apache.org/licenses/LICENSE-2.0
      #
      # Unless required by applicable law or agreed to in writing, software
      # distributed under the License is distributed on an "AS IS" BASIS,
      # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      # See the License for the specific language governing permissions and
      # limitations under the License.
      import sys
      import onnx
      
      INT_MAX = sys.maxsize
      
      if len(sys.argv) == 1:
          print("usage: python3.7 modify_yolov5.py model.onnx [n,c,h,w]")
          exit(0)
      
      model_path = sys.argv[1]
      model = onnx.load(model_path)
      
      b, c, h, w = 1, 3, 640, 640
      if len(sys.argv) == 3:
          b, c, h, w = list(map(int, sys.argv[2].split(',')))
          print(f"input shape: {b, c, h, w}")
      
      
      def get_node_by_name(nodes, name):
          for n in nodes:
              if n.name == name:
                  return n
          return -1
      
      """
      before:                           after:
                  input                             input
          /      /      \      \                /           \
      slice4 slice14 slice24 slice34        slice4        slice14
         |      |       |       |              |             |
      slice9 slice19 slice29 slice39           t              t
          \      \      /       /           /    \         /     \
                  concat                slice9 slice29 slice19 slice39
                                           |      |       |       |
                                           t      t       t       t
                                            \      \      /       /
                                                    concat
      """
      
      model.graph.node.remove(get_node_by_name(model.graph.node, "Slice_24"))
      model.graph.node.remove(get_node_by_name(model.graph.node, "Slice_34"))
      
      prob_info1 = onnx.helper.make_tensor_value_info('to_slice9', onnx.TensorProto.FLOAT, [b, c, h, w//2])
      prob_info3 = onnx.helper.make_tensor_value_info('to_slice19', onnx.TensorProto.FLOAT, [b, c, h, w//2])
      prob_info5 = onnx.helper.make_tensor_value_info('from_slice9', onnx.TensorProto.FLOAT, [b, c, h//2, w//2])
      prob_info6 = onnx.helper.make_tensor_value_info('from_slice19', onnx.TensorProto.FLOAT, [b, c, h//2, w//2])
      prob_info7 = onnx.helper.make_tensor_value_info('from_slice29', onnx.TensorProto.FLOAT, [b, c, h//2, w//2])
      prob_info8 = onnx.helper.make_tensor_value_info('from_slice39', onnx.TensorProto.FLOAT, [b, c, h//2, w//2])
      
      # slice4 slice24 后的Transpose,若自定义模型,inputs中的编号需根据onnx图中实际编号修改
      node1 = onnx.helper.make_node(
          'Transpose',
          inputs=[get_node_by_name(model.graph.node, "Slice_4").output[0]],
          outputs=['to_slice9'],
          perm=[0, 1, 3, 2]
      )
      node3 = onnx.helper.make_node(
          'Transpose',
          inputs=[get_node_by_name(model.graph.node, "Slice_14").output[0]],
          outputs=['to_slice19'],
          perm=[0, 1, 3, 2]
      )
      # slice9 slice19 slice29 slice39后的Transpose
      node5 = onnx.helper.make_node(
          'Transpose',
          inputs=['from_slice9'],
          outputs=[get_node_by_name(model.graph.node, "Slice_9").output[0]],
          perm=[0, 1, 3, 2]
      )
      node6 = onnx.helper.make_node(
          'Transpose',
          inputs=['from_slice19'],
          outputs=[get_node_by_name(model.graph.node, "Slice_19").output[0]],
          perm=[0, 1, 3, 2]
      )
      node7 = onnx.helper.make_node(
          'Transpose',
          inputs=['from_slice29'],
          outputs=[get_node_by_name(model.graph.node, "Slice_29").output[0]],
          perm=[0, 1, 3, 2]
      )
      node8 = onnx.helper.make_node(
          'Transpose',
          inputs=['from_slice39'],
          outputs=[get_node_by_name(model.graph.node, "Slice_39").output[0]],
          perm=[0, 1, 3, 2]
      )
      model.graph.node.append(node1)
      model.graph.node.append(node3)
      model.graph.node.append(node5)
      model.graph.node.append(node6)
      model.graph.node.append(node7)
      model.graph.node.append(node8)
      
      # slice9 slice19 换轴
      model.graph.initializer.append(onnx.helper.make_tensor('starts_9', onnx.TensorProto.INT64, [1], [0]))
      model.graph.initializer.append(onnx.helper.make_tensor('ends_9', onnx.TensorProto.INT64, [1], [INT_MAX]))
      model.graph.initializer.append(onnx.helper.make_tensor('axes_9', onnx.TensorProto.INT64, [1], [2]))
      model.graph.initializer.append(onnx.helper.make_tensor('steps_9', onnx.TensorProto.INT64, [1], [2]))
      newnode1 = onnx.helper.make_node(
          'Slice',
          name='Slice_9',
          inputs=['to_slice9', 'starts_9', 'ends_9', 'axes_9', 'steps_9'],
          outputs=['from_slice9']
      )
      model.graph.node.remove(get_node_by_name(model.graph.node, "Slice_9"))
      model.graph.node.insert(9, newnode1)
      newnode2 = onnx.helper.make_node(
          'Slice',
          name='Slice_19',
          inputs=['to_slice19', 'starts_9', 'ends_9', 'axes_9', 'steps_9'],
          outputs=['from_slice19']
      )
      model.graph.node.remove(get_node_by_name(model.graph.node, "Slice_19"))
      model.graph.node.insert(19, newnode2)
      
      # slice29 slice39 换轴
      model.graph.initializer.append(onnx.helper.make_tensor('starts_29', onnx.TensorProto.INT64, [1], [1]))
      model.graph.initializer.append(onnx.helper.make_tensor('ends_29', onnx.TensorProto.INT64, [1], [INT_MAX]))
      model.graph.initializer.append(onnx.helper.make_tensor('axes_29', onnx.TensorProto.INT64, [1], [2]))
      model.graph.initializer.append(onnx.helper.make_tensor('steps_29', onnx.TensorProto.INT64, [1], [2]))
      newnode3 = onnx.helper.make_node(
          'Slice',
          name='Slice_29',
          inputs=['to_slice9', 'starts_29', 'ends_29', 'axes_29', 'steps_29'],
          outputs=['from_slice29']
      )
      model.graph.node.remove(get_node_by_name(model.graph.node, "Slice_29"))
      model.graph.node.insert(29, newnode3)
      newnode4 = onnx.helper.make_node(
          'Slice',
          name='Slice_39',
          inputs=['to_slice19', 'starts_29', 'ends_29', 'axes_29', 'steps_29'],
          outputs=['from_slice39']
      )
      model.graph.node.remove(get_node_by_name(model.graph.node, "Slice_39"))
      model.graph.node.insert(39, newnode4)
      
      onnx.save(model, model_path.split('.')[0] + "_t.onnx")
      print("success")
      

      修改生成的onnx模型文件

      $ cd yolov5/weights
      $ python3.7 modify_yolov5.py yolov5s_sim.onnx #生成的模型名为:yolov5s_sim_t.onnx
      

1.3 升级DLAP221的系统

由于华为在CANN3.3.0版本及配套的1.0.9固件版本中针对yolov5做了优化,如果DLAP221的系统版本不是此版本,建议直接将DLAP221的SD系统整体升级到此版本。Adlink提供一键制卡工具包,方便客户制作该版本的系统。制卡工具包可以从以下的网盘地址下载。阅读工具包中README文件进行制卡。

  1. 制卡

    ###注意以下步骤,不要在Docker中执行,在PC机的Host环境(Ubuntu18.04)中执行!!!
    ###通过如下命令进行安装制卡工具包的系统依赖。
    $ sudo apt-get install -y qemu-user-static python3-yaml binfmt-support gcc-aarch64-linux-gnu g++-aarch64-linux-gnu expect unzip squashfs-tools
    #注意Ubuntu 18.04系统:“gcc-aarch64-linux-gnu”与“g++-aarch64-linux-gnu”版本要求为7.4.0,其他依赖软件包无版本要求。默认安装的gcc版本为7.4.0。
    $ tar xvf sd_maker_1.0.9_can3.3.0alpha006.tgz
    $ cd sd_maker
    #注意将micro SD卡插入PC机,如果PC机没有Micro SD卡槽,请用Micro SD读卡器进行转接。
    $ sudo python3.7.5 make_sd_card.py local /dev/sdX  #这里的sdX需要根据Micro SD卡插入Linux系统后生成的磁盘名来修改!!
    
  2. 启动系统

    将制好的卡插入DLAP221设备,上电启动,第一次启动系统会自动安装一些的平台依赖包和开发工具包,整个过程大概10多分钟,完成后系统会自动重启。建议用户接串口线来监视整个过程。串口波特率为115200 8N1,具体可以参考DLAP221的使用手册。

2. 模型转换

在DLAP221上完成ONNX模型到OM模型的转换

2.1 安装昇腾软件包

软件版本说明获取方式
mxManufacture2.0.1mxManufacture软件包mxManufacture下载页面 选择下载ARM安装包
Ascend-CANN-toolkit3.3.0.alpha006Ascend-cann-toolkit开发套件包,社区版社区版官网获取链接选择历史版本中的3.3.0.alpha006
  1. 安装Ascend Toolkit

    从上表中的链接下载toolkit,保存到/home/HwHiAiUser目录中并安装

    $  chmod +x Ascend-cann-toolkit_3.3.0.alpha006_linux-aarch64.run
    $ ./Ascend-cann-toolkit_3.3.0.alpha006_linux-aarch64.run --install --chip=Ascend310-minirc
    
  2. 安装mxManufacture

    从上表中的链接下载mxManufacture,保存到/home/HwHiAiUser目录中并安装

    $ chmod +x Ascend-mindxsdk-mxmanufacture_2.0.1_linux-aarch64.run
    $ ./Ascend-mindxsdk-mxmanufacture_2.0.1_linux-aarch64.run --install
    $ source ~/.bashrc # 激活mxManufacture环境变量
    

    运行结果:生成mxManufacture-2.0.1目录和mxManufacuture软链接。

2.2 模型转换

  1. 将Yolov5的ONNX模型拷贝到DLAP221上

    $ scp yolov5s_sim_t.onnx HwHiAiUser@<DLAP221的IP>:~/yolov5
    
  2. 创建aipp配置文件aipp_yolov5s.cfg, 并输入以下内容

    aipp_op { 
    aipp_mode : static
    related_input_rank : 0
    input_format : YUV420SP_U8
    src_image_size_w : 640
    src_image_size_h : 640
    crop : false
    csc_switch : true
    rbuv_swap_switch : false
    matrix_r0c0 : 256
    matrix_r0c1 : 0
    matrix_r0c2 : 359
    matrix_r1c0 : 256
    matrix_r1c1 : -88
    matrix_r1c2 : -183
    matrix_r2c0 : 256
    matrix_r2c1 : 454
    matrix_r2c2 : 0
    input_bias_0 : 0
    input_bias_1 : 128
    input_bias_2 : 128
    var_reci_chn_0 : 0.0039216
    var_reci_chn_1 : 0.0039216
    var_reci_chn_2 : 0.0039216
    }
    
  3. 模型转换

    $ source env.sh ##此步可选,默认制卡时已将环境变量设置好了
    $ atc --model=./yolov5s_sim_t.onnx \
        --framework=5 \
        --output=./yolov5s_sim_t \
     	--input_format=NCHW \
        --input_shape="images:1,3,640,640"  \
     	--enable_small_channel=1 \
        --insert_op_conf=./aipp_yolov5s.cfg \
        --soc_version=Ascend310 \
     	--log=info
    

3. 推理测试

3.1 准备

  1. 编写pipeline文件

    已为您编排好使用yolov5s进行目标检测的pipeline文件如下,该pipeline中只包括一条名为"classification+detection"的业务流,该业务流运行在0号芯片(DLAP221也只有一颗atlas200),由appsrc、mxpi_imagedecoder、mxpi_imageresize、mxpi_modelinfer、mxpi_dataserialize、appsink六个插件依次串连而成。注意,mxpi_imageresize插件设置缩放后的图片宽高为640*640且为等比缩放(“resizeType”: “Resizer_KeepAspectRatio_Fit”);mxpi_modelinfer插件中使用了与yolov5s_sim_t.om相适应的配置文件yolov5s.cfg和标签文件coco.names,均在此文档中提供。

    yolov5s_example.pipelines

    {
      "classification+detection": {
        "stream_config": {
          "deviceId": "0"
        },
        "mxpi_imagedecoder0": {
          "factory": "mxpi_imagedecoder",
          "next": "mxpi_imageresize0"
        },
        "mxpi_imageresize0": {
          "props": {
            "parentName": "mxpi_imagedecoder0",
            "resizeHeight": "640",
            "resizeWidth": "640",
            "resizeType": "Resizer_KeepAspectRatio_Fit"
          },
          "factory": "mxpi_imageresize",
          "next": "mxpi_modelinfer0"
        },s
        "mxpi_modelinfer0": {
          "props": {s
            "parentName": "mxpi_imageresize0",
            "modelPath": "../models/yolov5s/yolov5s_sim_t.om",
            "postProcessConfigPath": "../models/yolov5s/yolov5s.cfg",
            "labelPath": "../models/yolov5s/coco.names",
            "postProcessLibPath": "../../../lib/libMpYOLOv5PostProcessor.so"
          },
          "factory": "mxpi_modelinfer",
          "next": "mxpi_dataserialize0"
        },
        "mxpi_dataserialize0": {
          "props": {
            "outputDataKeys": "mxpi_modelinfer0"
          },
          "factory": "mxpi_dataserialize",
          "next": "appsink0"
        },
        "appsrc0": {
          "props": {
            "blocksize": "409600"
          },
          "factory": "appsrc",
          "next": "mxpi_imagedecoder0"
        },
        "appsink0": {
          "props": {
            "blocksize": "4096000"
          },
          "factory": "appsink"
        }
      }
    }
    

    将如上文件命名为yolov5s_example.pipeline,并保存至/home/HwHiAiUser/mxManufacture-2.0.1/samples/mxManufacture/pipeline目录。

  2. 编写yolov5s配置文件yolov5s.cfg

    CLASS_NUM=80
    BIASES_NUM=18
    BIASES=10,13,16,30,33,23,30,61,62,45,59,119,116,90,156,198,373,326
    SCORE_THRESH=0.6
    OBJECTNESS_THRESH=0.6
    IOU_THRESH=0.5
    YOLO_TYPE=3
    ANCHOR_DIM=3
    MODEL_TYPE=1
    RESIZE_FLAG=0
    

    将如上文件命名为yolov5s.cfg,并保存至/home/HwHiAiUser/mxManufacture-2.0.1/samples/mxManufacture/models/yolov5s目录。

  3. 标签文件coco.names

    # This file is originally from https://github.com/pjreddie/darknet/blob/master/data/coco.names
    person
    bicycle
    car
    motorbike
    aeroplane
    bus
    train
    truck
    boat
    traffic light
    fire hydrant
    stop sign
    parking meter
    bench
    bird
    cat
    dog
    horse
    sheep
    cow
    elephant
    bear
    zebra
    giraffe
    backpack
    umbrella
    handbag
    tie
    suitcase
    frisbee
    skis
    snowboard
    sports ball
    kite
    baseball bat
    baseball glove
    skateboard
    surfboard
    tennis racket
    bottle
    wine glass
    cup
    fork
    knife
    spoon
    bowl
    banana
    apple
    sandwich
    orange
    broccoli
    carrot
    hot dog
    pizza
    donut
    cake
    chair
    sofa
    pottedplant
    bed
    diningtable
    toilet
    tvmonitor
    laptop
    mouse
    remote
    keyboard
    cell phone
    microwave
    oven
    toaster
    sink
    refrigerator
    book
    clock
    vase
    scissors
    teddy bear
    hair drier
    toothbrush
    
    

    将如上文件命名为coco.names,并保存至/home/HwHiAiUser/mxManufacture-2.0.1/samples/mxManufacture/models/yolov5s目录。

  4. 离线模型文件

    拷贝yolov5s_sim_t.om文件到/home/HwHiAiUser/mxManufacture-2.0.1/samples/mxManufacture/models/yolov5s目录

至此,你已准备好运行yolov5s sample需要的所有文件

4. 推理应用调度代码开发

4.1 理解并运行sample code

  1. mxManufacture已为你准备好sample code,在/home/HwHiAiUser/mxManufacture-2.0.1/samples/mxManufacture/C++和/home/HwHiAiUser/mxManufacture-2.0.1/samples/mxManufacture/Python目录下。我们以C++代码为例,为了不影响默认提供的demo代码,我们另外在/home/HwHiAiUser/mxManufacture-2.0.1/samples/mxManufacture目录中创建一个文件夹:yolov5s_C++, 同时copy C++目录中的main.cpp和run.sh到我们新创建的目录。

    $ cd /home/HwHiAiUser/mxManufacture-2.0.1/samples/mxManufacture
    $ mkdir yolov5s_C++
    $ cp C++/main.cpp yolov5s_C++/
    $ cp C++/run.sh yolov5s_C++/
    $ ls
    main.cpp  run.sh
    
  2. 编辑main.cpp

    打开main.cpp文件,在main函数中指定待推理的图片(88行)和待创建的业务流编排文件(94行),然后依次调用mxManufacture初化接口(102行,InitManager,初化始日志级别等)、业务流创建接口(108行,CreateMultipleStreams,根据pipeline文件创建业务流)、发送推理请求接口(116行,SendData,发送推理请求,参数中指定业务流名称和待推理图片)、获取推理结果接口(122行,GetResult,获取推理结果)和业务流销毁接口(132行,DestroyAllStreams,程序退出前调用)。

      1 /*
      2  * Copyright (c) 2020.Huawei Technologies Co., Ltd. All rights reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16
     17 #include <cstring>
     18 #include "MxBase/Log/Log.h"
     19 #include "MxStream/StreamManager/MxStreamManager.h"
     20 namespace {
     21 APP_ERROR ReadFile(const std::string& filePath, MxStream::MxstDataInput& dataBuffer)
     22 {
     23     char c[PATH_MAX + 1] = { 0x00 };
     24     size_t count = filePath.copy(c, PATH_MAX + 1);
     25     if (count != filePath.length()) {
     26         LogError << "Failed to copy file path(" << c << ").";
     27         return APP_ERR_COMM_FAILURE;
     28     }
     29     // Get the absolute path of input file
     30     char path[PATH_MAX + 1] = { 0x00 };
     31     if ((strlen(c) > PATH_MAX) || (realpath(c, path) == nullptr)) {
     32         LogError << "Failed to get image, the image path is (" << filePath << ").";
     33         return APP_ERR_COMM_NO_EXIST;
     34     }
     35     // Open file with reading mode
     36     FILE *fp = fopen(path, "rb");
     37     if (fp == nullptr) {
     38         LogError << "Failed to open file (" << path << ").";
     39         return APP_ERR_COMM_OPEN_FAIL;
     40     }
     41     // Get the length of input file
     42     fseek(fp, 0, SEEK_END);
     43     long fileSize = ftell(fp);
     44     fseek(fp, 0, SEEK_SET);
     45     // If file not empty, read it into FileInfo and return it
     46     if (fileSize > 0) {
     47         dataBuffer.dataSize = fileSize;
     48         dataBuffer.dataPtr = new (std::nothrow) uint32_t[fileSize];
     49         if (dataBuffer.dataPtr == nullptr) {
     50             LogError << "allocate memory with \"new uint32_t\" failed.";
     51             return APP_ERR_COMM_FAILURE;
     52         }
     53
     54         uint32_t readRet = fread(dataBuffer.dataPtr, 1, fileSize, fp);
     55         if (readRet <= 0) {
     56             fclose(fp);
     57             return APP_ERR_COMM_READ_FAIL;
     58         }
     59         fclose(fp);
     60         return APP_ERR_OK;
     61     }
     62     fclose(fp);
     63     return APP_ERR_COMM_FAILURE;
     64 }
     65
     66 std::string ReadPipelineConfig(const std::string& pipelineConfigPath)
     67 {
     68     std::ifstream file(pipelineConfigPath.c_str(), std::ifstream::binary);
     69     if (!file) {
     70         LogError << pipelineConfigPath <<" file dose not exist.";
     71         return "";
     72     }
     73     file.seekg(0, std::ifstream::end);
     74     uint32_t fileSize = file.tellg();
     75     file.seekg(0);
     76     std::unique_ptr<char[]> data(new char[fileSize]);
     77     file.read(data.get(), fileSize);
     78     file.close();
     79     std::string pipelineConfig(data.get(), fileSize);
     80     return pipelineConfig;
     81 }
     82 }
     83
     84 int main(int argc, char* argv[])
     85 {
     86     // read image file and build stream input
     87     MxStream::MxstDataInput dataBuffer;
     88     APP_ERROR ret = ReadFile("./test.jpg", dataBuffer);
     89     if (ret != APP_ERR_OK) {
     90         LogError << GetError(ret) << "Failed to read image file.";
     91         return ret;
     92     }
     93     // read pipeline config file
     94     std::string pipelineConfigPath = "../pipeline/yolov5s_example.pipeline";
     95     std::string pipelineConfig = ReadPipelineConfig(pipelineConfigPath);
     96     if (pipelineConfig == "") {
     97         LogError << "Read pipeline failed.";
     98         return APP_ERR_COMM_INIT_FAIL;
     99     }
    100     // init stream manager
    101     MxStream::MxStreamManager mxStreamManager;
    102     ret = mxStreamManager.InitManager();
    103     if (ret != APP_ERR_OK) {
    104         LogError << GetError(ret) << "Failed to init Stream manager.";
    105         return ret;
    106     }
    107     // create stream by pipeline config file
    108     ret = mxStreamManager.CreateMultipleStreams(pipelineConfig);
    109     if (ret != APP_ERR_OK) {
    110         LogError << GetError(ret) << "Failed to create Stream.";
    111         return ret;
    112     }
    113     std::string streamName = "classification+detection";
    114     int inPluginId = 0;
    115     // send data into stream
    116     ret = mxStreamManager.SendData(streamName, inPluginId, dataBuffer);
    117     if (ret != APP_ERR_OK) {
    118         LogError << GetError(ret) << "Failed to send data to stream.";
    119         return ret;
    120     }
    121     // get stream output
    122     MxStream::MxstDataOutput* output = mxStreamManager.GetResult(streamName, inPluginId);
    123     if (output == nullptr) {
    124         LogError << "Failed to get pipeline output.";
    125         return ret;
    126     }
    127
    128     std::string result = std::string((char *)output->dataPtr, output->dataSize);
    129     LogInfo << "Results:" << result;
    130
    131     // destroy streams
    132     mxStreamManager.DestroyAllStreams();
    133     delete dataBuffer.dataPtr;
    134     dataBuffer.dataPtr = nullptr;
    135
    136     delete output;
    137     return 0;
    138 }
    
    

    实际开发时,用户可以参考如上代码调用mxManufacture的五个接口:InitManager, CreateMultipleStreams, SendData, GetResult, DestroyAllStreams, 即可在自己的推理应用中使用mxManufacture进行推理了。这里我们指定业务流编排文件为3.1中编写好的yolov5s_example.pipeline文件,图片使用C++目录下的默认图片(test.jpg,是一张背景纯白的狗),无需修改。在C++目录下运行如下命令,可在日志中看到推理结果。

    $ bash run.sh
    省略部分输出....
    I0518 04:23:20.026540  7934 MxGstBase.cpp:764] element(mxpi_imageresize0) gst_change_state NULL_TO_READY.
    I0518 04:23:20.026688  7934 MxGstBase.cpp:632] element(mxpi_imageresize0) dynamicImageSize=640,640;
    I0518 04:23:20.026892  7934 MxGstBase.cpp:764] element(mxpi_imagedecoder0) gst_change_state NULL_TO_READY.
    I0518 04:23:20.027192  7934 MxStreamManager.cpp:384] Creates stream(classification+detection) successfully.
    I0518 04:23:20.027390  7934 MxStreamManager.cpp:434] Creates streams successfully.
    I0518 04:23:20.075621  7934 main.cpp:129] Results:{"MxpiObject":[{"classVec":[{"classId":16,"className":"dog","confidence":0.67863529899999997,"headerVec":   []}],"x0":72.779052699999994,"x1":941.77044699999999,"y0":132.82678200000001,"y1":604.33477800000003}]} ##此行为推理结果!!
    I0518 04:23:20.075755  7934 MxsmStream.cpp:688] Begin to destroy stream(classification+detection).
    I0518 04:23:20.075904  7934 MxsmStream.cpp:743] Send custom eos to the Stream successfully.
    I0518 04:23:20.076239  7934 MxsmStream.cpp:749] Send eos to the Stream successfully.
    I0518 04:23:20.076385  7934 MxsmStream.cpp:755] Flushes the Stream data successfully.
    省略部分输出....
    

4.2 推理结果可视化&性能打点

为将推理结果更加直观地显示并简单测试推理性能,对run.sh脚本和main.cpp文件作简单修改:

  • run.sh脚本包含opencv的头文件和引入opencv_world动态库。

    #!/bin/bash
    
    # Copyright 2020 Huawei Technologies Co., Ltd
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    # http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    set -e
    
    CUR_PATH=$(cd "$(dirname "$0")" || { warn "Failed to check path/to/run.sh" ; exit ; } ; pwd)
    
    # Simple log helper functions
    info() { echo -e "\033[1;34m[INFO ][MxStream] $1\033[1;37m" ; }
    warn() { echo >&2 -e "\033[1;31m[WARN ][MxStream] $1\033[1;37m" ; }
    
    export MX_SDK_HOME="${CUR_PATH}/../../.."
    export LD_LIBRARY_PATH="${MX_SDK_HOME}/lib":"${MX_SDK_HOME}/opensource/lib":"${MX_SDK_HOME}/opensource/lib64":"/usr/local/Ascend/ascend-toolkit/latest/acllib/lib64":${LD_LIBRARY_PATH}
    export GST_PLUGIN_SCANNER="${MX_SDK_HOME}/opensource/libexec/gstreamer-1.0/gst-plugin-scanner"
    export GST_PLUGIN_PATH="${MX_SDK_HOME}/opensource/lib/gstreamer-1.0":"${MX_SDK_HOME}/lib/plugins"
    
    # complie
    ###包含opencv的头文件和引入opencv_world动态库
    g++ main.cpp -I "${MX_SDK_HOME}/include/" -I "${MX_SDK_HOME}/opensource/include/"  -I "${MX_SDK_HOME}/opensource/include/opencv4" -L "${MX_SDK_HOME}/lib/" -L "${MX_SDK_HOME}/opensource/lib/" -L "${MX_SDK_HOME}/opensource/lib64/" -std=c++11 -D_GLIBCXX_USE_CXX11_ABI=0 -Dgoogle=mindxsdk_private -fPIC -fstack-protector-all -g -Wl,-z,relro,-z,now,-z,noexecstack -pie -Wall -lglog -lmxbase -lmxpidatatype -lplugintoolkit -lstreammanager -lcpprest -lmindxsdk_protobuf -lopencv_world -o main
    
    # run
    ./main
    
    
  • main.cpp添加利用opencv显示坐标框和性能打点代码。

    • 第20行插入如下代码

      #include "opencv4/opencv2/opencv.hpp"
      
    • 第116行插入如下代码

      auto startTime = std::chrono::high_resolution_clock::now();
      
    • 第125-128行插入如下代码

      auto endTime = std::chrono::high_resolution_clock::now();
      double costMs = std::chrono::duration<double, std::milli>(endTime - startTime).count();
      LogInfo << "[SendData-GetResult] cost: " << costMs << "ms. ";
      LogInfo << "[SendData-GetResult] fps: " << 1000/costMs << "fps";
      
    • 第137-173行插入如下代码

      web::json::value jsonText = web::json::value::parse(result); 
      if (jsonText.is_object()) { 
          web::json::object textObject = jsonText.as_object(); 
          auto itInferObject = textObject.find("MxpiObject"); 
          if (itInferObject == textObject.end() || (!itInferObject->second.is_array())) { 
              return 0; 
          } 
          auto iter = itInferObject->second.as_array().begin(); 
          cv::Mat src = cv::imread("./test.jpg"); 
          for (; iter != itInferObject->second.as_array().end(); iter++) { 
              if (iter->is_object()) { 
                  auto modelInferObject = iter->as_object(); 
                  float x0 = 0; 
                  float x1 = 0; 
                  float y0 = 0; 
                  float y1 = 0; 
                  auto it = modelInferObject.find("x0"); 
                  if (it != modelInferObject.end()) { 
                      x0 = float(it->second.as_double()); 
                  } 
                  it = modelInferObject.find("x1"); 
                  if (it != modelInferObject.end()) { 
                      x1 = float(it->second.as_double()); 
                  } 
                  it = modelInferObject.find("y0"); 
                  if (it != modelInferObject.end()) { 
                      y0 = float(it->second.as_double()); 
                  } 
                  it = modelInferObject.find("y1"); 
                  if (it != modelInferObject.end()) { 
                      y1 = float(it->second.as_double()); 
                  } 
                  cv::Rect rect(x0, y0, x1 - x0, y1 - y0); 
                  cv::rectangle(src, rect, cv::Scalar(0, 255, 0),5, cv::LINE_8,0); 
              } 
          } 
          cv::imwrite("./result.jpg", src); 
      }
      

修改完后的代码如下:

  1 /*
  2  * Copyright (c) 2020.Huawei Technologies Co., Ltd. All rights reserved.
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *     http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16
 17 #include <cstring>
 18 #include "MxBase/Log/Log.h"
 19 #include "MxStream/StreamManager/MxStreamManager.h"
 20 #include "opencv4/opencv2/opencv.hpp"
 21 namespace {
 22 APP_ERROR ReadFile(const std::string& filePath, MxStream::MxstDataInput& dataBuffer)
 23 {
 24     char c[PATH_MAX + 1] = { 0x00 };
 25     size_t count = filePath.copy(c, PATH_MAX + 1);
 26     if (count != filePath.length()) {
 27         LogError << "Failed to copy file path(" << c << ").";
 28         return APP_ERR_COMM_FAILURE;
 29     }
 30     // Get the absolute path of input file
 31     char path[PATH_MAX + 1] = { 0x00 };
 32     if ((strlen(c) > PATH_MAX) || (realpath(c, path) == nullptr)) {
 33         LogError << "Failed to get image, the image path is (" << filePath << ").";
 34         return APP_ERR_COMM_NO_EXIST;
 35     }
 36     // Open file with reading mode
 37     FILE *fp = fopen(path, "rb");
 38     if (fp == nullptr) {
 39         LogError << "Failed to open file (" << path << ").";
 40         return APP_ERR_COMM_OPEN_FAIL;
 41     }
 42     // Get the length of input file
 43     fseek(fp, 0, SEEK_END);
 44     long fileSize = ftell(fp);
 45     fseek(fp, 0, SEEK_SET);
 46     // If file not empty, read it into FileInfo and return it
 47     if (fileSize > 0) {
 48         dataBuffer.dataSize = fileSize;
 49         dataBuffer.dataPtr = new (std::nothrow) uint32_t[fileSize];
 50         if (dataBuffer.dataPtr == nullptr) {
 51             LogError << "allocate memory with \"new uint32_t\" failed.";
 52             return APP_ERR_COMM_FAILURE;
 53         }
 54
 55         uint32_t readRet = fread(dataBuffer.dataPtr, 1, fileSize, fp);
 56         if (readRet <= 0) {
 57             fclose(fp);
 58             return APP_ERR_COMM_READ_FAIL;
 59         }
 60         fclose(fp);
 61         return APP_ERR_OK;
 62     }
 63     fclose(fp);
 64     return APP_ERR_COMM_FAILURE;
 65 }
 66
 67 std::string ReadPipelineConfig(const std::string& pipelineConfigPath)
 68 {
 69     std::ifstream file(pipelineConfigPath.c_str(), std::ifstream::binary);
 70     if (!file) {
 71         LogError << pipelineConfigPath <<" file dose not exist.";
 72         return "";
 73     }
 74     file.seekg(0, std::ifstream::end);
 75     uint32_t fileSize = file.tellg();
 76     file.seekg(0);
 77     std::unique_ptr<char[]> data(new char[fileSize]);
 78     file.read(data.get(), fileSize);
 79     file.close();
 80     std::string pipelineConfig(data.get(), fileSize);
 81     return pipelineConfig;
 82 }
 83 }
 84
 85 int main(int argc, char* argv[])
 86 {
 87     // read image file and build stream input
 88     MxStream::MxstDataInput dataBuffer;
 89     APP_ERROR ret = ReadFile("./test.jpg", dataBuffer);
 90     if (ret != APP_ERR_OK) {
 91         LogError << GetError(ret) << "Failed to read image file.";
 92         return ret;
 93     }
 94     // read pipeline config file
 95     std::string pipelineConfigPath = "../pipeline/yolov5s_example.pipeline";
 96     std::string pipelineConfig = ReadPipelineConfig(pipelineConfigPath);
 97     if (pipelineConfig == "") {
 98         LogError << "Read pipeline failed.";
 99         return APP_ERR_COMM_INIT_FAIL;
100     }
101     // init stream manager
102     MxStream::MxStreamManager mxStreamManager;
103     ret = mxStreamManager.InitManager();
104     if (ret != APP_ERR_OK) {
105         LogError << GetError(ret) << "Failed to init Stream manager.";
106         return ret;
107     }
108     // create stream by pipeline config file
109     ret = mxStreamManager.CreateMultipleStreams(pipelineConfig);
110     if (ret != APP_ERR_OK) {
111         LogError << GetError(ret) << "Failed to create Stream.";
112         return ret;
113     }
114     std::string streamName = "classification+detection";
115     int inPluginId = 0;
116     // send data into stream
117     auto startTime = std::chrono::high_resolution_clock::now();
118     ret = mxStreamManager.SendData(streamName, inPluginId, dataBuffer);
119     if (ret != APP_ERR_OK) {
120         LogError << GetError(ret) << "Failed to send data to stream.";
121         return ret;
122     }
123     // get stream output
124     MxStream::MxstDataOutput* output = mxStreamManager.GetResult(streamName, inPluginId);
125     auto endTime = std::chrono::high_resolution_clock::now();
126     double costMs = std::chrono::duration<double, std::milli>(endTime - startTime).count();
127     LogInfo << "[SendData-GetResult] cost: " << costMs << "ms. ";
128     LogInfo << "[SendData-GetResult] fps: " << 1000/costMs << "fps";
129     if (output == nullptr) {
130         LogError << "Failed to get pipeline output.";
131         return ret;
132     }
133
134     std::string result = std::string((char *)output->dataPtr, output->dataSize);
135     LogInfo << "Results:" << result;
136
137     web::json::value jsonText = web::json::value::parse(result);
138     if (jsonText.is_object()) {
139         web::json::object textObject = jsonText.as_object();
140         auto itInferObject = textObject.find("MxpiObject");
141         if (itInferObject == textObject.end() || (!itInferObject->second.is_array())) {
142             return 0;
143         }
144         auto iter = itInferObject->second.as_array().begin();
145         cv::Mat src = cv::imread("./test.jpg");
146         for (; iter != itInferObject->second.as_array().end(); iter++) {
147             if (iter->is_object()) {
148                 auto modelInferObject = iter->as_object();
149                 float x0 = 0;
150                 float x1 = 0;
151                 float y0 = 0;
152                 float y1 = 0;
153                 auto it = modelInferObject.find("x0");
154                 if (it != modelInferObject.end()) {
155                     x0 = float(it->second.as_double());
156                 }
157                 it = modelInferObject.find("x1");
158                 if (it != modelInferObject.end()) {
159                     x1 = float(it->second.as_double());
160                 }
161                 it = modelInferObject.find("y0");
162                 if (it != modelInferObject.end()) {
163                     y0 = float(it->second.as_double());
164                 }
165                 it = modelInferObject.find("y1");
166                 if (it != modelInferObject.end()) {
167                     y1 = float(it->second.as_double());
168                 }
169                 cv::Rect rect(x0, y0, x1 - x0, y1 - y0);
170                 cv::rectangle(src, rect, cv::Scalar(0, 255, 0),5, cv::LINE_8,0);
171             }
172         }
173         cv::imwrite("./result.jpg", src);
174     }
175     // destroy streams
176     mxStreamManager.DestroyAllStreams();
177     delete dataBuffer.dataPtr;
178     dataBuffer.dataPtr = nullptr;
179
180     delete output;
181     return 0;
182 }


再回到yolov5s_C++目录,运行bash run.sh,日志显示, 处理时间为:49.491ms. 平均帧率为:20.2057fps, test.jpg的分辨率为:1024x683

$ bash run.sh
省略部分输出...
I0518 05:48:41.255576  8093 MxGstBase.cpp:632] element(mxpi_imageresize0) dynamicImageSize=640,640;
I0518 05:48:41.255784  8093 MxGstBase.cpp:764] element(mxpi_imagedecoder0) gst_change_state NULL_TO_READY.
I0518 05:48:41.256076  8093 MxStreamManager.cpp:384] Creates stream(classification+detection) successfully.
I0518 05:48:41.256207  8093 MxStreamManager.cpp:434] Creates streams successfully.
I0518 05:48:41.305809  8093 main.cpp:131] [SendData-GetResult] cost: 49.491ms.
I0518 05:48:41.305980  8093 main.cpp:132] [SendData-GetResult] fps: 20.2057fps
I0518 05:48:41.306020  8093 main.cpp:135] Results:{"MxpiObject":[{"classVec":[{"classId":16,"className":"dog","confidence":0.67103165399999998,"headerVec":[]}],"x0":71.558685299999993,"x1":943.03247099999999,"y0":132.90640300000001,"y1":604.41442900000004}]}
I0518 05:48:41.377825  8093 MxsmStream.cpp:688] Begin to destroy stream(classification+detection).
I0518 05:48:41.378067  8093 MxsmStream.cpp:743] Send custom eos to the Stream successfully.
I0518 05:48:41.378247  8093 MxsmStream.cpp:749] Send eos to the Stream successfully.
I0518 05:48:41.378386  8093 MxsmStream.cpp:755] Flushes the Stream data successfully.
I0518 05:48:41.378731  8093 MxGstBase.cpp:770] element(mxpi_dataserialize0) gst_change_state PLAYING_TO_PAUSED.
I0518 05:48:41.378816  8093 MxGstBase.cpp:770] element(mxpi_modelinfer0) gst_change_state PLAYING_TO_PAUSED.
I0518 05:48:41.378883  8093 MxGstBase.cpp:770] element(mxpi_imageresize0) gst_change_state PLAYING_TO_PAUSED.
I0518 05:48:41.378957  8093 MxGstBase.cpp:770] element(mxpi_imagedecoder0) gst_change_state PLAYING_TO_PAUSED.
I0518 05:48:41.379127  8093 MxGstBase.cpp:773] element(mxpi_dataserialize0) gst_change_state PAUSED_TO_READY.
省略部分输出...

和当前目录生成的result.jpg图片如下。

推理结果图片

5. 纯推理测试

4.2中的推理性能是端到端的性能,其中包括了图像预处理和推理结果的后处理时间,现在我们测试模型的纯推理时间。

5.1 下载benchmark工具

网盘下载benchmark工具,提取码:5uzu,并解压缩到/home/HwHiAiUser目录

$ cd /home/HwHiAiUser
$ unzip Ascend-cann-benchmark_5.0.1-Linux-aarch64.zip

5.2 性能测试

$ cd /home/HwHiAiUser/mxManufacture/samples/mxManufacture/models/yolov5s
$ sudo /home/HwHiAiUser/benchmark_tools/benchmark.aarch64 -batch_size=1 -om_path=./yolov5s_sim_t.om -round=50 -device_id=0
[INFO][Inference] PureInfer Init SUCCESS
[INFO] Dataset number: 0 finished cost 24.818ms
[INFO] Dataset number: 1 finished cost 9.682ms
[INFO] Dataset number: 2 finished cost 9.714ms
[INFO] Dataset number: 3 finished cost 9.707ms
[INFO] Dataset number: 4 finished cost 9.658ms
[INFO] Dataset number: 5 finished cost 9.704ms
[INFO] Dataset number: 6 finished cost 9.686ms
[INFO] Dataset number: 7 finished cost 9.612ms
[INFO] Dataset number: 8 finished cost 9.588ms
[INFO] Dataset number: 9 finished cost 9.631ms
[INFO] Dataset number: 10 finished cost 9.614ms
[INFO] Dataset number: 11 finished cost 9.721ms
[INFO] Dataset number: 12 finished cost 9.677ms
[INFO] Dataset number: 13 finished cost 9.717ms
[INFO] Dataset number: 14 finished cost 9.671ms
[INFO] Dataset number: 15 finished cost 9.652ms
[INFO] Dataset number: 16 finished cost 9.672ms
[INFO] Dataset number: 17 finished cost 9.594ms
[INFO] Dataset number: 18 finished cost 9.622ms
[INFO] Dataset number: 19 finished cost 9.624ms
[INFO] Dataset number: 20 finished cost 9.671ms
[INFO] Dataset number: 21 finished cost 9.621ms
[INFO] Dataset number: 22 finished cost 9.682ms
[INFO] Dataset number: 23 finished cost 9.75ms
[INFO] Dataset number: 24 finished cost 9.736ms
[INFO] Dataset number: 25 finished cost 9.645ms
[INFO] Dataset number: 26 finished cost 9.657ms
[INFO] Dataset number: 27 finished cost 9.59ms
[INFO] Dataset number: 28 finished cost 9.631ms
[INFO] Dataset number: 29 finished cost 9.61ms
[INFO] Dataset number: 30 finished cost 9.616ms
[INFO] Dataset number: 31 finished cost 9.651ms
[INFO] Dataset number: 32 finished cost 9.671ms
[INFO] Dataset number: 33 finished cost 9.661ms
[INFO] Dataset number: 34 finished cost 9.71399ms
[INFO] Dataset number: 35 finished cost 9.691ms
[INFO] Dataset number: 36 finished cost 9.69ms
[INFO] Dataset number: 37 finished cost 9.666ms
[INFO] Dataset number: 38 finished cost 9.62ms
[INFO] Dataset number: 39 finished cost 9.607ms
[INFO] Dataset number: 40 finished cost 9.591ms
[INFO] Dataset number: 41 finished cost 9.63ms
[INFO] Dataset number: 42 finished cost 9.633ms
[INFO] Dataset number: 43 finished cost 9.66ms
[INFO] Dataset number: 44 finished cost 9.71ms
[INFO] Dataset number: 45 finished cost 9.706ms
[INFO] Dataset number: 46 finished cost 9.688ms
[INFO] Dataset number: 47 finished cost 9.665ms
[INFO] Dataset number: 48 finished cost 9.616ms
[INFO] Dataset number: 49 finished cost 9.617ms
[INFO] PureInfer result saved in ./result/PureInfer_perf_of_yolov5s_sim_t_in_device_0.txt
-----------------PureInfer Performance Summary------------------
[INFO] ave_throughputRate: 103.547samples/s, ave_latency: 9.9612ms
----------------------------------------------------------------

6. 基于SDK的推理代码开发

6.1 下载样例代码

从https://gitee.com/shiner-chen/APISamples获取最新的样例代码。

$ git clone git@gitee.com:shiner-chen/APISamples.git

6.2 编译运行

$ cd APISamples/src/Samples/InferObjectDetection
$ bash build.sh YOLOV5
$ cd dist 
$ ./main -i test.jpg -t 2
[Info ][2021-05-20 11:39:19:411328][ResourceManager.cpp InitResource:75] Initialized acl successfully.
[Info ][2021-05-20 11:39:19:505191][ResourceManager.cpp InitResource:84] Open device 0 successfully.
[Info ][2021-05-20 11:39:19:506968][ResourceManager.cpp InitResource:91] Created context for device 0 successfully
[Info ][2021-05-20 11:39:19:507094][ResourceManager.cpp InitResource:102] Init resource successfully.
[Info ][2021-05-20 11:39:19:507272][AclProcess.cpp InitResource:161] Create context successfully
[Info ][2021-05-20 11:39:19:507957][AclProcess.cpp InitResource:167] Create stream successfully
[Info ][2021-05-20 11:39:19:523990][AclProcess.cpp InitModule:121] Initialize dvppCommon_ successfully
[Info ][2021-05-20 11:39:19:524167][ModelProcess.cpp Init:240] ModelProcess:Begin to init instance.
[Info ][2021-05-20 11:39:19:839716][AclProcess.cpp InitModule:139] Initialize ModelProcess_ successfully
[Info ][2021-05-20 11:39:19:856578][AclProcess.cpp InitModule:145] Loaded label successfully.
[Info ][2021-05-20 11:39:19:884394][AclProcess.cpp YoloPostProcess:503] The number of output buffers of yolov3 model is 3
[Info ][2021-05-20 11:39:19:903552][AclProcess.cpp YoloPostProcess:528] #Obj0, box(33.537, 122.282, 955.744, 612.067)   confidence: 0.777343 label: dog
[Info ][2021-05-20 11:39:19:903891][AclProcess.cpp YoloPostProcess:535] [Process Delay] cost: 47.1801ms fps: 21.1954
[Info ][2021-05-20 11:39:19:942970][AclProcess.cpp Release:71] Destroy stream successfully
[Info ][2021-05-20 11:39:19:943135][ModelProcess.cpp DeInit:150] Model[yolov3][0] deinit begin
[Info ][2021-05-20 11:39:19:965709][ModelProcess.cpp DeInit:189] Model[yolov3][0] deinit success
[Info ][2021-05-20 11:39:19:973285][ResourceManager.cpp Release:44] Finalized acl successfully.

$ ls ./result/result_test.jpg
result_test.jpg

生成的结果图片:

推理结果图片

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值