VS2019使用C++调用并部署pytorch VGG模型全过程(libtorch+opencv)(cpu+gpu)

环境配置vs2019+libtorch1.9.0+opencv3.4.2+cuda11.0+cudnn8.0(实测可用,不踩坑)

须知

Libtorch版本需与pytorch版本兼容(最好一致),系统下载与pytorch版本相同的CUDA和Cudnn,否则导入模型将出错。
若想使程序在GPU上运行,需下载GPU版libtorch,其也支持cpu运行。
文中给出图片或许版本与标题不一致,不影响实际操作,作者已亲测可行

libtorch

用C++调用pytorch模型,其目的在于:使用C++及多线程可以加快模型预测速度

模型训练有两种方法:
1.直接使用C++编写训练代码,搭建完整的网络模型,但此方法无法使用迁移学习,而迁移学习是目前训练样本几乎都会用到的方法
2.使用python代码训练好模型,使用JIT技术,将python模型导出为C++可调用的模型

TorchScript:一种从PyTorch代码创建可序列化和可优化模型的方法。用TorchScript编写的任何代码都可以从Python进程中保存并加载到没有Python依赖关系的进程中。
利用工具可增量地将模型从纯Python程序转换为能够独立于Python运行的TorchScript程序,例如,一个独立的c++程序。

实验流程

1.安装librtorch(有gpu和cpu版本,都可实现)

[1] pytorch官网.
在这里插入图片描述
[2] 某博主整理的libtorch各版本下载地址.👍!
【gpu版本需要在电脑上安装对应的版本的cuda和cudnn! 】

2.安装opencv

opencv官网.
官网下载opencv库压缩包,解压至本地

3.python端:

(1)搭建pytorch网络模型(以vgg分类网络为例)

(2)将PyTorch模型转换为Torch Script Module
第一个方法是tracing。该方法通过将样本输入到模型中一次,来对该过程进行评估从而捕获模型结构,并记录该样本在模型中的flow。该方法适用于模型中很少使用控制flow的模型。
第二个方法就是向模型添加显式注释,通知Torch Script编译器它可以直接解析和编译模型代码,受Torch Script语言强加的约束。

用Tracing将模型转换为Torch Script (无论后续选择用cpu或gpu,此步操作相同)
要通过tracing来将PyTorch模型转换为Torch脚本,必须将模型的实例以及样本输入传递给torch.jit.trace函数,并在模块的forward方法中嵌入模型评估的跟踪,这将生成一个torch.jit.ScriptModule对象,最后将该对象保存(即将ScriptModule序列化为一个文件。然后,C++就可以不依赖任何Python代码来执行该Script所对应的Pytorch模型。)。

【导入模型:(按照自己保存模型的方式进行导入:直接保存模型or保存权重参数)】
这里是保存的权重参数信息…
在这里插入图片描述
【提供任意输入张量(size需符合网络输入要求):】
在这里插入图片描述
【将输入送入网络,追踪模型所有操作】
序列化模型时,模型和输入在cpu上运算
在这里插入图片描述
【保存序列化后模型:】
在这里插入图片描述
跟踪的ScriptModule可以与常规PyTorch模块进行相同的计算

tips:以上代码针对输入单个图像送入网络的情况,后续将更新如何将孪生网络(输入两个图像)模型序列化并在C++中调用的博客

3.C++端

(1)在VS中配置libtorch库
创建新项目;
配置头文件(项目->属性);
在这里插入图片描述
配置库目录;
在这里插入图片描述

添加依赖库的文件名(此处为确保libtorch的所有相关lib文件被导入,可写为~lib\*.lib
在这里插入图片描述
tips:
在这里插入图片描述
(2)在VS(2019)中配置opencv库
Vc++目录 >

包含目录:
~\OpenCV\build\include
~\OpenCV\build\include\opencv
~\OpenCV\build\include\opencv2

库目录:
~\OpenCV\build\x64\vc15\lib

链接器>附加依赖项:
opencv_world342d.lib (对应debug)
opencv_world342.lib (对应release)

(3)在C++中加载和执行Script Module
要在C ++中加载序列化的PyTorch模型,必须依赖于PyTorch C ++ API - 也称为LibTorch。
即创建最终调用网络模型.cpp文件;(cpu运行可直接在新项目中创建,gpu运行需单独创建
【导入头文件】
在这里插入图片描述
【载入模型】
模型路径中必须是’\\';路径中可以有中文(但一般路径最好不用中文!),必须是绝对路径;

在这里插入图片描述
*argv[[1]]为序列化后模型的路径(此为官方例程,实际自用时可用自定义string model_path 替代),如下:
在这里插入图片描述
【执行模型】
在这里插入图片描述
创建一个torch :: jit :: IValue的向量并添加一个输入。
要创建输入张量,我们可以使用torch :: ones(),相当于C ++ API中的torch.ones。

在这里插入图片描述
然后运行script::Module的forward方法,将我们创建的输入向量传递给它。最后调用**.toTensor() **将其转换为张量。

(4)LibTorch构建应用程序(生成.exe文件)
【CPU版本:】
可在vs中直接创建项目,在项目中创建.cpp文件,再直接点击运行进行调试
【GPU版本:】
先创建.cpp文件,再配置CMakeLists.txt来建立项目,最后在cmd中通过cmake编译项目,生成.exe可执行程序。如下:
1、执行(3),将代码保存到名为main.cpp的文件中。

2、构建它的CMakeLists.txt

cmake_minimum_required(VERSION 3.0 )   # 指定cmake的最小版本
project(gpucode)     # 设置项目名称

SET(CMAKE_BUILE_TYPE Debug)
 
find_package(Torch REQUIRED)

set(OpenCV_DIR D:/opencv3.4.2/build)
set(OpenCV_MODULE_PATH D:/opencv3.4.2/build)
find_package(OpenCV REQUIRED)

include_directories( ${OpenCV_INCLUDE_DIRS} )    # 需要用到opencv,则需要配置
include_directories( ${Torch_INCLUDE_DIRS} )

message(STATUS "Pytorch status:")
message(STATUS "    libraries: ${TORCH_LIBRARIES}")
message(STATUS "OpenCV library status:")
message(STATUS "    version: ${OpenCV_VERSION}")
message(STATUS "    libraries: ${OpenCV_LIBS}")
message(STATUS "    include path: ${OpenCV_INCLUDE_DIRS}")

add_executable(gpucode main.cpp)  # 生成可执行文件  
target_link_libraries(gpucode "${TORCH_LIBRARIES}" "${OpenCV_LIBS}")    # 设置 target 需要链接的库
set_property(TARGET gpucode PROPERTY CXX_STANDARD 11)

在这里插入图片描述
构建应用程序时,假设我们的目录布局如下:

		F:/C++code/gpucode1/
		    CMakeLists.txt
		    main.cpp

3、CMD中运行以下命令从gpucode1/文件夹中构建应用程序:

【1】cd "F:\C++code\gpucode1"

再输入:

【2】cmake -DCMAKE_PREFIX_PATH="F:\C++code\gpucode1"

DCMAKE_PREFIX_PATH:该路径为生成项目的位置,路径下需包含CMakeLists.txt

【若出现以下报错】(即未指定生成项目使用的平台类型)在这里插入图片描述
==》将指令改为:

cmake -DCMAKE_PREFIX_PATH="F:\C++code\gpucode1" -G "Visual Studio 15 2017 Win64"

[tip]:网上有的方法写的是加上:

运行出现:(路径只是举例说明)在这里插入图片描述
说明指令是从运行目录的上一级寻找所需文件,所以不写[..]可避免问题发生。


若又出现下错误:(即与之前使用的生成器不匹配)
在这里插入图片描述
解决方法:删除CMakeCache.txt, 重新运行指令即可

【3】make           

make可用cmake --build . --config Debug/Release替代,(Debug/Release具体看自己的C++代码选择的调试模式),效果一致】

如果一切顺利,它将出现以下语句:

➀ Cmake-DCMAKE_PREFIX_PATH="F:\C++code\gpucode1"

在这里插入图片描述
➁ cmake --build . --config Debug
在这里插入图片描述
在这里插入图片描述

4.结果比较

使用相同的序列化模型(.pt文件)通过libtorch在vs上运行来尝试。通过比较,发现C++端的输出与Python端的输出是一样的,表明实验成功。
CMD对应路径下运行gpucode.exe文件:
tip)若使用的是torch.jit.load(argv[1]),运行时记得添加.pt文件对应路径,如 :

gpucode.exe(空格)d:/model.pt

否则:

gpucode.exe

在这里插入图片描述
Pycharm运行.py文件:
在这里插入图片描述

常见问题

1.利用cpu运行时,占用率太高
在这里插入图片描述
2.验证c++端gpu是否可用
std::cout << torch::cuda::is_available() << std::endl;
返回值=1,即可。为0表示显卡未调用起来
在这里插入图片描述

/INCLUDE:?warp_size@cuda@at@@YAHXZ

(将原有的%(AdditionalOptions) /machine:x64)删除)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
初次应用GPU时,会有预热过程,耗时较长

3.GPU版编译成功,但运行到model.to(at::KCUDA)报错或无反应
[[1]]检查GPU是否能够成功调用
[[2]]检查是否按照教程利用cmake进行编译,不可直接在vs软件进行调试

4.torch::jit::load()导入模型运行无反应或导入失败
[[1]]序列化模型时,模型和输入不需指定在gpu上进行计算
即不需有下语句:
device=”gpu” ; model=model.to(device) ;x=x. cuda()
[[2]]检查训练py网络模型的pytorch版本是否和libtorch版本一致
[[3]]尝试利用cmake进行编译

5.报错找不到.dll文件
检查配置环境,若仍无法解决,则将缺失dll文件直接复制于项目目录下(或.exe所在目录下)

6.报错无法定位程序输入点于动态链接库 .exe上
在这里插入图片描述
[[1]].检查项目路径中是否有中文
[[2]].是否在利用cmake生成可执行文件前,在vs中进行了调试(即点击了本地windows调试器)?
----清理已生成的解决方案,再重新用cmake编译
----若上无效,建议重新创建项目

7.cmake报错opencv not found
在这里插入图片描述
用记事本打开路径对应的OpenCVConfig.cmake文件,修改最后 OpenCV_FOUND为TRUE

8.比较cpu和gpu运算时间差异
c++端:

	#include<windows.h>
	double start= GetTickCount();    //得到系统运行时间 单位为ms
	double  end = GetTickCount();

python端:

	import time
	starttime = time.time()
	endtime = time.time()
	time = endtime - starttime

9.找不到libtorch的配置文件
在这里插入图片描述
在Cmakelists.txt中find_package(Torch REQUIRED)前面加入下语句:
在这里插入图片描述
路径为上述配置文件所在文件夹的绝对路径

10.无法解析的外部函数
cpu:检查项目–>属性–>链接库配置,重新生成解决方案
gpu:检查项目–>属性–>链接库配置,重新执行cmake第二步。若修改后重新运行问题依然存在,则在vs中先清理解决方案,再在cmd中重新cmake

------tbc-------
有用可以点个大拇指哦 🤭

【作者有话说】
以上内容仅为博主自主整理分享,很多内容也是来源于网络,若有侵权,请私聊告知
大家有任何问题可在评论区讨论交流~

  • 9
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

8倍

谢谢大佬~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值