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 exporttry:import onnxprint('\nStarting ONNX export with onnx %s...' % onnx.__version__)f = opt.weights.replace('.pt', '.onnx')  # filenamemodel.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'])# Checksonnx_model = onnx.load(f)  # load onnx modelonnx.checker.check_model(onnx_model)  # check onnx modelprint(onnx.helper.printable_graph(onnx_model.graph))  # print a human readable modelprint('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.2API version:       1.41Go version:        go1.13.8Git commit:        20.10.2-0ubuntu1~18.04.2Built:             Tue Mar 30 21:24:16 2021OS/Arch:           linux/amd64Context:           defaultExperimental:      trueServer:Engine:Version:          20.10.2API version:      1.41 (minimum version 1.12)Go version:       go1.13.8Git commit:       20.10.2-0ubuntu1~18.04.2Built:            Mon Mar 29 19:27:41 2021OS/Arch:          linux/amd64Experimental:     falsecontainerd:Version:          1.3.3-0ubuntu1~18.04.4GitCommit:runc:Version:          spec: 1.0.2-devGitCommit:docker-init:Version:          0.19.0GitCommit:$ 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.ptStarting ONNX export with onnx 1.9.0...
      ...
      ONNX export success, saved as ./weights/yolov5s.onnxStarting 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.mlmodelExport 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 onnxINT_MAX = sys.maxsizeif 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 nreturn -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 安装昇腾软件包

软件 版本 说明 获取方式
mxManufacture 2.0.1 mxManufacture软件包 mxManufacture下载页面 选择下载ARM安装包
Ascend-CANN-toolkit 3.3.0.alpha006 Ascend-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 at7  *8  *     http://www.apache.org/licenses/LICENSE-2.09  *10  * Unless required by applicable law or agreed to in writing, software11  * 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 and14  * limitations under the License.15  */1617 #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 file30     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 mode36     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 file42     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 it46     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         }5354         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 }6566 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 }8384 int main(int argc, char* argv[])85 {86     // read image file and build stream input87     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 file94     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 -eCUR_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 at7  *8  *     http://www.apache.org/licenses/LICENSE-2.09  *10  * Unless required by applicable law or agreed to in writing, software11  * 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 and14  * limitations under the License.15  */1617 #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 file31     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 mode37     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 file43     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 it47     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         }5455         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 }6667 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 }8485 int main(int argc, char* argv[])86 {87     // read image file and build stream input88     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 file95     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

生成的结果图片:

DLAP221上Yolov5s性能测试相关推荐

  1. 使用OpenVINO优化和部署DenseNet模型并在DevCloud上完成性能测试

    概述 Intel® DevCloud for the Edge支持在英特尔的硬件平台上主动构建原型并试验面向计算机视觉的AI 工作负载.其硬件平台托管在云环境中,专门用于深度学习,用户可以全面访问这些 ...

  2. 在DLAP221上部署容器进行推理操作

    1. Install toolbox 根据设备驱动版本,安装对应版本的Ascend-cann-toolbox_x.x.x_linux-aarch64.run,我的驱动版本是21.0.1,在此我安装的t ...

  3. 3测试图片显示置信度_云上的移动性能测试平台

    1. 功能决定现在,性能决定未来 性能测试在移动测试领域一直是一个大难题,它最直观的表现是用户在前台使用 App 时的主观体验,然而决定体验优劣的背后,涉及到了许许多多的技术变迁. 当我们习惯于诺基亚 ...

  4. ldap客户端工具_什么是性能测试?性能测试主流工具有哪些?

    性能测试的概念 一般来说,性能是一种指标,表明软件系统或构件对其及时性要求的符合程度;其次,性能是软件产品的一种特性,可以用时间来进行度量.性能的及时性用响应时间或吞吐量来衡量.响应时间是指服务器对请 ...

  5. 七月新增开源项目:你学习的速度跟得上前端造轮子的速度吗?

    2019独角兽企业重金招聘Python工程师标准>>> 每月新增开源项目.顾名思义,每月更新一期.我们会从社区上个月新收录的开源项目中,挑选出有价值的.有用的.优秀的.或者好玩的开源 ...

  6. python递归合并排序_python 归并排序的递归法与迭代法(利用队列)实现,以及性能测试...

    递归排序核心 递归排序的核心是 分与合 分的最终结果 就是将原数组中每一个数字分作一个数组, 合就是 所有小数组不断排序,合并的过程. 合并的过程是先将两个含有一个数字的数组排序,合并(每次比较两个数 ...

  7. “纹身贴皮电路“:未来在皮肤上画个电路就能监测身体健康状况

    导读 从人体皮肤中准确提取生理和物理信号对于健康监测.疾病预防和治疗至关重要.可穿戴生物电子学的最新进展直接嵌入到表皮表面是未来表皮传感的一个很有前途的解决方案.然而,现有的可穿戴生物电子学容易受到运 ...

  8. 聊聊性能测试、操作系统优化对性能测试的影响,以及如何优化操作系统

    序 男生追女生方法名堂层出不穷,而女生追男生好像招数不多.写情书寻常女子肯定低不下这个头,于是找男生"修电脑"成了跨域祖国大江南北,甚至我们台湾人民的不二选择.很可惜,我读大学的时 ...

  9. 在做性能测试之前需要知道什么

    以下是我自己录制的关于这篇文章的一小段视频,有兴趣的可以下载看看 https://yunpan.cn/cPQc4mm2DjbMu  访问密码 a76f //此篇摘抄于虫师博客,个人觉得通俗易懂 关于理 ...

最新文章

  1. c语言指针实现字符串倒序输出,菜鸟求助-如何用指针法将一串字符按单词的倒序输出?如:i love yo...
  2. 图像配准----NCC
  3. 内核-syn-ack RTO修改
  4. ​多分类下的ROC曲线和AUC​
  5. 什么是倾斜45度的火山图?
  6. 数据科学 IPython 笔记本 8.11 多个子图
  7. Helm 3 完整教程(二十):在 Helm 模板中定义和使用变量
  8. 十分钟用Django创建一个简单的职位管理系统
  9. java liveness_并发 - 活跃度(Liveness) - 《Java 编程要点(Essential Java)》 - 书栈网 · BookStack...
  10. 卷积神经网络(CNN)卷积核与滤波器理解
  11. 超级经典的Word技巧
  12. ArcGIS Server 发布服务失败
  13. 降噪蓝牙耳机对比测评:南卡和OPPO哪款降噪耳机好?
  14. 解决thinkpad或者其他笔记本电脑无线网络不可用问题
  15. 我的汉语名字叫东坤,可以帮我起一个读音相近的英语名字吗
  16. HashMap和TreeMap
  17. RNC/SGSN/PDP/IUPS概念
  18. Java阿凯_彩虹城堡之七彩宝石篇最终版攻略
  19. 【BUG解决】 RuntimeError: Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor)
  20. learnopengl 中 pbr的球体算法

热门文章

  1. 深刻理解GPIO(上拉输入、下拉输入、模拟输入、浮空输入,开漏输出,推挽输出的区别,以STM32为例)
  2. 数据结构栈(顺序栈、链栈、插入push、删除pop)、队(循环队,链队、入队push,出队pop)知识点梳理
  3. 前端自动化构建工具合集之webpack-姜威-专题视频课程
  4. linux 测试端口通不通
  5. 如何使用py2exe,以及解决ImportError: No module named py2exe问题
  6. win10防火墙怎么关闭端口?
  7. kfold_提示Kfold对象不可迭代
  8. Nokia5230刷机呕心历程
  9. 结合布林线理解现货白银走势图的方法
  10. html5 回到顶部按钮,“返回顶部”按钮效果