mmdetection模型使用mmdeploy部署在windows上的c++部署流程【详细全面版】

0. 前置说明:

该文档适用于:已经使用mmdetection训练好了模型,并且完成了模型转换。要进行模型部署了。

1. 概述

MMDeploy 定义的模型部署流程,如下图所示:

模型转换【待撰写,敬请期待...】

主要功能是:把输入的模型格式,转换为目标设备的推理引擎所要求的模型格式。

目前,MMDeploy 可以实现:

  • ① 把PyTorch 模型,转换为 ONNX、TorchScript 等和设备无关的 IR 模型;
  • ② 将 ONNX 模型转换为推理后端模型。

两者相结合,可实现端到端的模型转换,也就是从训练端到生产端的一键式部署。

MMDeploy 模型(也称 SDK Model)

它是模型转换结果的集合。包括:①后端模型,②模型的元信息。这些信息,将用于推理 SDK。

推理  SDK【本博客的内容】

封装了模型的前处理、网络推理和后处理过程。对外提供多语言的模型推理接口(python/c++等)。【注意:本教程为c++】

2. 准备工作

对于端到端的模型转换和推理,MMDeploy 依赖 Python 3.6+ 以及 PyTorch 1.8+。

第1步:下载并安装 Miniconda

(这步很简单,省略,不懂的话可以评论区留言)

第2步:创建并激活 conda 环境

conda create --name mmdeploy python=3.8 -y
conda activate mmdeploy

第3步: 并安装 PyTorch GPU或者CPU版本。

链接:安装PyTorch

注意❗:在 GPU 环境下,请务必保证 cudatoolkit_version 和主机的 CUDA Toolkit 版本一致,避免在使用 TensorRT 时,可能引起的版本冲突问题。

3. 准备推理SDK

第1步: 安装 MMDeploy 推理SDK

推理SDK 的 c/cpp 库可从 这里 选择最新版本下载并安装。

不用gpu推理的话,就下载这个

注意❗下载并且解压后,就会看到如下图所示的结构:

路径为:C:\Users\15135\Downloads\mmdeploy-1.2.0-windows-amd64

原始目录1

|-----build_sdk.ps1
|-----install_opencv.ps1
|-----README.md
|-----set_env.ps1
|-----bin
     |-----mmdeploy.dll
     |-----mmdeploy_ort_net.dll
|-----example
     |-----cpp
          |-----CMakeLists.txt
          |-----c
               |-----batch_image_classification.cpp
               |-----batch_object_detection.cpp
               |-----det_cls.cpp
               |-----det_pose.cpp
               |-----image_classification.cpp
               |-----image_restorer.cpp
               |-----image_segmentation.cpp
               |-----object_detection.cpp
               |-----ocr.cpp
               |-----pose_detection.cpp
               |-----rotated_object_detection.cpp
               |-----video_recognition.cpp
          |-----cpp
               |-----classifier.cxx
               |-----detector.cxx
               |-----det_pose.cxx
               |-----pose_detector.cxx
               |-----pose_tracker.cxx
               |-----pose_tracker_params.h
               |-----restorer.cxx
               |-----rotated_detector.cxx
               |-----segmentor.cxx
               |-----text_det_recog.cxx
               |-----text_ocr.cxx
               |-----video_cls.cxx
               |-----utils
                    |-----argparse.h
                    |-----mediaio.h
                    |-----palette.h
                    |-----skeleton.h
                    |-----visualize.h
     |-----python
          |-----det_pose.py
          |-----image_classification.py
          |-----image_restorer.py
          |-----image_segmentation.py
          |-----object_detection.py
          |-----ocr.py
          |-----pipeline.py
          |-----pose_detection.py
          |-----pose_tracker.py
          |-----rotated_object_detection.py
          |-----video_recognition.py
|-----include
     |-----mmdeploy
          |-----classifier.h
          |-----classifier.hpp
          |-----common.h
          |-----common.hpp
          |-----detector.h
          |-----detector.hpp
          |-----executor.h
          |-----model.h
          |-----pipeline.h
          |-----pipeline.hpp
          |-----pose_detector.h
          |-----pose_detector.hpp
          |-----pose_tracker.h
          |-----pose_tracker.hpp
          |-----restorer.h
          |-----restorer.hpp
          |-----rotated_detector.h
          |-----rotated_detector.hpp
          |-----segmentor.h
          |-----segmentor.hpp
          |-----text_detector.h
          |-----text_detector.hpp
          |-----text_recognizer.h
          |-----text_recognizer.hpp
          |-----video_recognizer.h
          |-----video_recognizer.hpp
          |-----archive
               |-----json_archive.h
               |-----value_archive.h
          |-----core
               |-----archive.h
               |-----device.h
               |-----device_impl.h
               |-----graph.h
               |-----logger.h
               |-----macro.h
               |-----mat.h
               |-----model.h
               |-----model_impl.h
               |-----module.h
               |-----net.h
               |-----operator.h
               |-----profiler.h
               |-----registry.h
               |-----serialization.h
               |-----status_code.h
               |-----tensor.h
               |-----types.h
               |-----value.h
               |-----mpl
                    |-----detected.h
                    |-----iterator.h
                    |-----priority_tag.h
                    |-----span.h
                    |-----static_any.h
                    |-----structure.h
                    |-----type_traits.h
               |-----utils
                    |-----device_utils.h
                    |-----filesystem.h
                    |-----formatter.h
                    |-----source_location.h
                    |-----stacktrace.h
          |-----experimental
               |-----module_adapter.h
          |-----third_party
               |-----json
                    |-----json.hpp
               |-----outcome
                    |-----outcome-experimental.hpp
               |-----spdlog
                    |-----async.h
                    |-----async_logger-inl.h
                    |-----async_logger.h
                    |-----common-inl.h
                    |-----common.h
                    |-----formatter.h
                    |-----fwd.h
                    |-----logger-inl.h
                    |-----logger.h
                    |-----pattern_formatter-inl.h
                    |-----pattern_formatter.h
                    |-----spdlog-inl.h
                    |-----spdlog.h
                    |-----stopwatch.h
                    |-----tweakme.h
                    |-----version.h
                    |-----cfg
                         |-----argv.h
                         |-----env.h
                         |-----helpers-inl.h
                         |-----helpers.h
                    |-----details
                         |-----backtracer-inl.h
                         |-----backtracer.h
                         |-----circular_q.h
                         |-----console_globals.h
                         |-----file_helper-inl.h
                         |-----file_helper.h
                         |-----fmt_helper.h
                         |-----log_msg-inl.h
                         |-----log_msg.h
                         |-----log_msg_buffer-inl.h
                         |-----log_msg_buffer.h
                         |-----mpmc_blocking_q.h
                         |-----null_mutex.h
                         |-----os-inl.h
                         |-----os.h
                         |-----periodic_worker-inl.h
                         |-----periodic_worker.h
                         |-----registry-inl.h
                         |-----registry.h
                         |-----synchronous_factory.h
                         |-----tcp_client-windows.h
                         |-----tcp_client.h
                         |-----thread_pool-inl.h
                         |-----thread_pool.h
                         |-----udp_client-windows.h
                         |-----udp_client.h
                         |-----windows_include.h
                    |-----fmt
                         |-----bin_to_hex.h
                         |-----chrono.h
                         |-----compile.h
                         |-----fmt.h
                         |-----ostr.h
                         |-----ranges.h
                         |-----xchar.h
                         |-----bundled
                              |-----args.h
                              |-----chrono.h
                              |-----color.h
                              |-----compile.h
                              |-----core.h
                              |-----fmt.license.rst
                              |-----format-inl.h
                              |-----format.h
                              |-----locale.h
                              |-----os.h
                              |-----ostream.h
                              |-----printf.h
                              |-----ranges.h
                              |-----xchar.h
                    |-----sinks
                         |-----android_sink.h
                         |-----ansicolor_sink-inl.h
                         |-----ansicolor_sink.h
                         |-----base_sink-inl.h
                         |-----base_sink.h
                         |-----basic_file_sink-inl.h
                         |-----basic_file_sink.h
                         |-----daily_file_sink.h
                         |-----dist_sink.h
                         |-----dup_filter_sink.h
                         |-----hourly_file_sink.h
                         |-----mongo_sink.h
                         |-----msvc_sink.h
                         |-----null_sink.h
                         |-----ostream_sink.h
                         |-----qt_sinks.h
                         |-----ringbuffer_sink.h
                         |-----rotating_file_sink-inl.h
                         |-----rotating_file_sink.h
                         |-----sink-inl.h
                         |-----sink.h
                         |-----stdout_color_sinks-inl.h
                         |-----stdout_color_sinks.h
                         |-----stdout_sinks-inl.h
                         |-----stdout_sinks.h
                         |-----syslog_sink.h
                         |-----systemd_sink.h
                         |-----tcp_sink.h
                         |-----udp_sink.h
                         |-----wincolor_sink-inl.h
                         |-----wincolor_sink.h
                         |-----win_eventlog_sink.h
|-----lib
     |-----mmdeploy.lib
     |-----mmdeploy_ort_net.lib
     |-----cmake
          |-----MMDeploy
               |-----loader.cpp.in
               |-----MMDeploy.cmake
               |-----MMDeployConfig.cmake
               |-----MMDeployConfigVersion.cmake
               |-----MMDeployTargets-release.cmake
               |-----MMDeployTargets.cmake
               |-----modules
                    |-----FindCUDNN.cmake
                    |-----FindONNXRUNTIME.cmake
                    |-----FindTENSORRT.cmake
                    |-----FindTVM.cmake
|-----thirdparty
     |-----onnxruntime
          |-----include
               |-----cpu_provider_factory.h
               |-----cuda_provider_factory.h
               |-----onnxruntime_cxx_api.h
               |-----onnxruntime_cxx_inline.h
               |-----onnxruntime_c_api.h
               |-----onnxruntime_run_options_config_keys.h
               |-----onnxruntime_session_options_config_keys.h
               |-----provider_options.h
          |-----lib
               |-----onnxruntime.dll
               |-----onnxruntime.lib
               |-----onnxruntime.pdb
               |-----onnxruntime_providers_shared.dll

查看readme.md文档,就会发现,我们需要进一步根据提示:①安装opencv,②设置环境变量,③创建sdk。下面我们依次进行。

ReadMe文档内容:说明了如何在Windows系统中通过PowerShell命令行构建一个SDK(Software Development Kit)
# 1.首先
你需要以管理员身份运行PowerShell,并设置执行策略为RemoteSigned【这将允许本地创建和远程签名的脚本运行】

# 2.安装OpenCV
如果你还没有安装OpenCV,在SDK文件夹中运行. \install_opencv.ps1脚本来自动安装OpenCV。如果已安装,则可跳过此步骤。

# 3.设置环境变量和路径
在SDK文件夹中运行. .\set_env.ps1脚本,它会为你配置相关的环境变量和系统路径。
如果你使用的是含CUDA版本的SDK,除了需要额外安装CUDA和cuDNN之外,可能还需要手动设置指向cuDNN根目录的环境变量。

# 4.构建SDK
还是在SDK文件夹中,根据你的OpenCV安装方式运行相应的命令:

如果你使用. \install_opencv.ps1脚本安装了OpenCV,直接运行. \build_sdk.ps1。
如果你是自己安装的OpenCV,需要提供OpenCV配置文件所在的路径,运行. \build_sdk.ps1 "path/to/folder/of/OpenCVConfig.cmake"。

# 5.执行完上述命令后
SDK将会被构建完成,生成的可执行文件将会存储在example\cpp\build\Release目录下。

第2步: 安装opencv

  • 找到Windows PowerShell,并使用管理员身份打开。

打开管理员权限的 Windows PowerShell

  • 打开Windows PowerShell后,执行命令:set-ExecutionPolicy RemoteSigned,并选择Y。
Set-ExecutionPolicy RemoteSigned 是一个在 Microsoft PowerShell 中使用的命令。
它用来配置 PowerShell 的执行策略(Execution Policy),这是 PowerShell 引擎对脚本执行的一种安全机制。
执行策略决定了 PowerShell 是否允许运行未签名的脚本,以及这些脚本是从何处获得的。具体来说:

在Windows PowerShell中设置执行策略为`RemoteSigned`的主要目的是:
为了确保系统的安全性和对脚本执行的控制。
PowerShell执行策略是用来控制是否允许PowerShell脚本在系统上运行的一个安全机制。

- RemoteSigned 执行策略意味着:
  - 对于本地创建的 PowerShell 脚本,无需签名也可以运行。
  - 对于从互联网或其他外部源下载的 PowerShell 脚本,必须经过数字签名验证才能执行。
这意味着如果一个脚本是从网络上下载的,那么它需要有一个可信的数字签名来证明其来源可靠且未经篡改。
这样可以防止恶意脚本在未经许可的情况下被执行,从而保护系统不受潜在威胁。

因此,在准备安装软件包、配置环境变量或执行其他系统级修改操作时,
通常会建议用户首先以管理员权限运行PowerShell,并将执行策略设置为RemoteSigned,以便能够顺利执行必要的脚本程序。

在这个特定的场景中,你可能需要运行一些PowerShell脚本来自动化安装OpenCV和构建SDK的过程,
而这些脚本,可能包含了系统级别的更改操作,所以需要适当的执行策略支持。


如果不执行 `Set-ExecutionPolicy RemoteSigned` 命令
如果不执行 `Set-ExecutionPolicy RemoteSigned` 命令来更改PowerShell的执行策略,可能会导致以下情况:

1. 
如果当前的执行策略设置更为严格,比如设为 `Restricted`,则不允许任何未签名的脚本(包括本地和远程)执行。
在这种情况下,当你尝试运行一些用于安装依赖项(如OpenCV)、配置环境变量或编译项目的PowerShell脚本时,
PowerShell会拒绝执行这些脚本,并给出错误提示。

2. 
如果当前策略已经较为宽松(如 `AllSigned` 或 `Unrestricted`),则该步骤不是必需的。
但出于安全考虑,`RemoteSigned` 是一种折衷方案,它既能确保从互联网下载的脚本有安全签名,
又能允许本地创建的脚本不受限制地运行。

总结来说,不执行 `Set-ExecutionPolicy RemoteSigned` 可能会影响到后续通过PowerShell脚本进行的自动化配置和构建工作无法正常进行。
在实际操作时,请根据具体的安全需求和环境设定来调整执行策略。
  • 在Windows PowerShell环境下,可以使用`Get-AuthenticodeSignature` cmdlet来查看PowerShell脚本是否有数字签名。以下是查看脚本是否经过数字签名的步骤:
# 指定脚本文件路径
$scriptPath = "C:\Path\To\Your\Script.ps1"

# 使用 Get-AuthenticodeSignature cmdlet 检查脚本签名
$signature = Get-AuthenticodeSignature $scriptPath

# 输出签名信息
$signature.SignerCertificate # 显示签名证书信息
$signature.Status           # 显示签名状态(Valid、Invalid、NotSigned等)

# 如果脚本已签名,则Status字段应显示为"Valid",否则会显示"NotSigned"

运行上述命令后,如果脚本已被数字签名,`Get-AuthenticodeSignature` 将返回签名详细信息,包括签名人、颁发者、有效期等,并且 Status 字段会显示 "Valid"。

如果没有签名,则 Status 会显示 "NotSigned"。(如下图)

NotSigned

  • 进入(cd)预编译包的文件夹路径解压位置。

  • 手动下载opencv4.5.5(源码,需要自己从 官网 下载)到指定位置,本示例为:

C:\Users\15135\Downloads\mmdeploy-1.2.0-windows-amd64\opencv-4.5.5.zip。

注意,要保证opencv-4.5.5的内容如下:

  • 修改install_opencv.ps1源码,并保存。如下:
$opencvVer = "4.5.5"  # 设置OpenCV版本

$ErrorActionPreference = 'Stop'  # 设置错误处理策略为终止脚本执行
$WORKSPACE = $PSScriptRoot  # 获取脚本所在的工作目录路径
$THIRDPARTY_DIR = "${WORKSPACE}/thirdparty"  # 设置第三方库存储的目录路径
$OPENCV_DIR = "${THIRDPARTY_DIR}/opencv/install"  # 设置OpenCV安装目录路径

if (-Not (Test-Path -Path $THIRDPARTY_DIR -PathType Container)) {
    New-Item -Path $THIRDPARTY_DIR -ItemType Directory  # 如果第三方库目录不存在,则创建该目录
}

Push-Location "${THIRDPARTY_DIR}"  # 切换到第三方库目录

# 指定已下载的OpenCV压缩文件路径
$zipFilePath = "C:\Users\15135\Downloads\mmdeploy-1.2.0-windows-amd64\opencv-4.5.5.zip"

# 解压缩OpenCV压缩文件到指定目录
Expand-Archive -Path $zipFilePath -DestinationPath "${THIRDPARTY_DIR}/opencv" -Force

Push-Location "${THIRDPARTY_DIR}/opencv/opencv-${opencvVer}"  # 进入解压后的"opencv"目录
New-Item -Path "build" -ItemType Directory  # 在"opencv"目录中创建"build"目录
Push-Location build  # 进入"build"目录

cmake .. -A x64 -T v142 `
    -DBUILD_TESTS=OFF `
    -DBUILD_PERF_TESTS=OFF `
    -DCMAKE_INSTALL_PREFIX="${OPENCV_DIR}"  # 使用CMake配置构建选项

cmake --build . --config Release -j6  # 使用CMake构建OpenCV
cmake --install . --config Release  # 安装OpenCV到指定目录

Pop-Location  # 返回上一级目录
Pop-Location  # 返回上一级目录
Pop-Location  # 返回上一级目录

深耕AI:cmake .. -A x64 -T v142 `如何理解?【全面详细】1 赞同 · 0 评论文章​编辑

install_opencv.ps1中的这段脚本,是一个自动化安装 OpenCV 的过程,涵盖了下载解压、配置编译选项、编译和安装等步骤。通过执行此脚本,用户可以方便快捷地在 Windows 系统上安装指定版本的 OpenCV 库。

这段 PowerShell 脚本主要实现以下功能:

设置 OpenCV 版本为 4.5.5。
设定错误处理策略为遇到错误立即停止脚本执行。
获取当前脚本所在的工作目录,并基于此设置第三方库目录和 OpenCV 安装目录。
检查第三方库目录是否存在,若不存在则创建该目录。

切换到第三方库目录。
指定已下载好的 OpenCV 压缩文件路径。
解压缩 OpenCV 压缩文件到第三方库目录下的 opencv 文件夹。
创建 opencv 目录下的 build 子目录,并进入该子目录。

使用 CMake 配置 OpenCV 的编译选项,包括关闭测试和性能测试、指定安装目录以及选择 Visual Studio 的编译工具链。
使用 CMake 构建 OpenCV 的 Release 版本,并使用多线程(这里指定为6线程)进行编译。
使用 CMake 安装构建好的 OpenCV 到之前指定的安装目录。
最后,逐级返回至上一级目录,恢复原始工作目录。

深耕AI:PowerShell 脚本的后缀名,为什么叫.ps1?如何运行?1 赞同 · 0 评论文章​编辑

  • 指定CMake环境

命令为:$env:Path += ";C:\Program Files\CMake\bin"

深耕AI:cmake到底是个啥?【详细说】`$env:Path += ";C:\Program Files\CMake\bin"`【命令解释】1 赞同 · 0 评论文章​编辑

  • 运行代码install_opencv.ps1(比较耗时)

不报错,并出现如下提示,说明opencv安装成功!

opencv安装完成

第3步:设置环境变量

使用命令:

. .\set_env.ps1

第4步:构建 SDK

在这之前,我们要先删除一些文件。

  • ① 删除example下的python文件夹。

  • ② 删除\example\cpp\cpp下的文件,只剩下detector。

  • 并且要修改 CMakeLists.txt


修改为如下(主要是删除了其他的项目,只保留detector):

# 版权声明:OpenMMLab。保留所有权利。
# CMake最低版本要求
cmake_minimum_required(VERSION 3.14)

# 项目名称
project(mmdeploy-example)

# 检查是否需要MMDeploy,并在需要时查找它
if (NOT (${CMAKE_PROJECT_NAME} STREQUAL "MMDeploy"))
    find_package(MMDeploy REQUIRED)
endif ()

# 定义一个函数用于添加示例
function(add_example task folder name)
    # 检查任务是否指定,或者是否在MMDEPLOY_TASKS列表中
    if ((NOT task) OR (task IN_LIST MMDEPLOY_TASKS))
        # 在指定的文件夹中搜索名为name的cp源文件
        file(GLOB _SRCS ${folder}/${name}.c*)
        # 创建一个可执行目标,并将找到的源文件添加进去
        add_executable(${name} ${_SRCS})
        # 对于非MSVC和非苹果平台,禁用新的动态标签,以便即使未设置LD_LIBRARY_PATH,可执行文件也能正常运行
        if (NOT (MSVC OR APPLE))
            target_link_libraries(${name} PRIVATE -Wl,--disable-new-dtags)
        endif ()
        # 如果是单体SDK构建,则链接mmdeploy和OpenCV库到目标
        if (MMDEPLOY_BUILD_SDK_MONOLITHIC)
            target_link_libraries(${name} PRIVATE mmdeploy ${OpenCV_LIBS})
        else ()
            # 加载MMDeploy模块
            mmdeploy_load_static(${name} MMDeployStaticModules)
            mmdeploy_load_dynamic(${name} MMDeployDynamicModules)
            # 链接MMDeploy库
            target_link_libraries(${name} PRIVATE MMDeployLibs ${OpenCV_LIBS})
        endif ()
        # 安装目标到bin目录
        install(TARGETS ${name} RUNTIME DESTINATION bin)
    endif ()
endfunction()

# 添加各个示例
add_example(detector cpp detector)
  • 构建sdk命令为:
. .\build_sdk.ps1

之后,就会看到多了一个build文件,里面的内容如下:

4. 进行推理

第1步:VS2019 双击sln启动项目

  • 切换到release状态,右击detector项目,重新生成。

  • 在release目录下,点击生成的exe

会报错如下:

解决方案:将如下dll拷贝到release下。

  • 然后,在mmdeploy-1.2.0-windows-amd64\example\cpp\build\Release目录下,使用cmd运行exe,就不报错了,如下。

但是,由于缺少参数的传递,给有任何结果。

因为在cpp源码中,我们是需要通过命令行参数,去传递模型文件的地址,以及待预测的图像路径的。

第2步:拷贝模型和图像

将转换后的模型文件和待预测图像,放到对应文件夹中。

img是图像存放文件夹,model是模型文件夹

模型文件

然后,再运行exe,并跟上模型文件目录和图像的路径,就会出现预测结果:

并且,我们可以看到生成了原图的分割结果图,如下。

实例分割后结果图

第3步:修改源码

一般情况下,官方提供的代码都并不能直接拿过来进行部署到生产环境,那么这个时候,我们就需要进行修改cpp源码。比如,我们使用下面的这个代码:

detector参数写到了代码中1个图.cxx

然后,重新编译。这个时候,直接运行exe,不需要输入参数,就可以得到预测结果,如下。

注意:如果你不想生成exe,而是要在其他cpp代码中调用这个结果并进行处理。那么,就需要生成为动态库dll。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值