欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Win10 + VS2019 + Qt5 + Pytorch C++ cmake 基本配置

程序员文章站 2024-03-12 22:59:21
...

最近想用 Qt 写一个界面在 C++ 下调用 Pytorch 模型,整个环境配置下来遇到了不少问题,因此记录一下。

1. 下载安装相关文件

由于我的开发环境是 Win10,因此需要下载的东西挺多的,IDE 用的 Visual Studio 2019,在 这里 下载社区版,安装的时候可以选择需要的编译器,我装的是 MSVC v142,cmake 也可以在 vs2019 里直接装,或者自己下载单独的 cmake 安装。

在 cmd 里输入 cmake 以确保能够正常使用,如果不行,需要把 cmake 的 bin 目录添加到系统环境变量中。

Win10 + VS2019 + Qt5 + Pytorch C++ cmake 基本配置

然后下载 Qt5,在 清华源 里可以直接下载,在页面右边的获取下载链接的应用软件里。Qt 正常安装就可以了。

Win10 + VS2019 + Qt5 + Pytorch C++ cmake 基本配置
Pytorch 有专门的 C++ 库,叫 Libtorch,在 官网 上就可以下载到。这里我选择的是 cpu 版本的,cuda 版本的还需要额外的配置,先把简单的搞定。

Python 和 C++ 的 Pytorch 版本最好一样,免得读取模型出问题,我这里统一用了 1.6 版本。

Win10 + VS2019 + Qt5 + Pytorch C++ cmake 基本配置
下载完成,解压后放到一个文件夹里就行。

2. 转换 Pytorch 模型

这一步需要将 Pytorch 模型转换成 Torch Script,这东西具体是个啥可以看 官方文档

转换模型可以有两种方法,第一种是 tracing,使用一个示例输入来获取模型结构。
第二种是在模型中添加显式 annotations,以告知 Torch Script 编译器可以根据 Torch Script 语言施加的约束直接解析和编译模型代码。

2.1 通过 Tracing 转换

import torch
import torchvision

# 模型实例
model = torchvision.models.resnet18()

# 设置一个示例输入
example = torch.rand(1, 3, 224, 224)

# 使用 torch.jit.trace 生成 torch.jit.ScriptModule
traced_script_module = torch.jit.trace(model, example)

# 保存转换后的模型
traced_script_module.save("traced_resnet_model.pt")

2.2 通过 Annotation 转换

如果模型有特定的控制流,例如控制流依赖于输入:

import torch

class MyModule(torch.nn.Module):
    def __init__(self, N, M):
        super(MyModule, self).__init__()
        self.weight = torch.nn.Parameter(torch.rand(N, M))

    def forward(self, input):
        if input.sum() > 0:
          output = self.weight.mv(input)
        else:
          output = self.weight + input
        return output

可以通过 torch.jit.script 将模块转换为 ScriptModule。

my_module = MyModule(10,20)
sm = torch.jit.script(my_module)

# 保存模型
my_module.save("my_module_model.pt")

3. 新建项目

新建项目时我用的不是 vs2019,而是 Qt Creator,因为 Libtorch 给的是 cmake 的构建方式,使用 Qt 新建 cmake 项目时会建立所有需要的东西。

新建一个 widget 应用。

Win10 + VS2019 + Qt5 + Pytorch C++ cmake 基本配置
这里选择 cmake。

Win10 + VS2019 + Qt5 + Pytorch C++ cmake 基本配置
项目建立完成后可以选择直接用 Qt Creator 写,也可以用 vs2019 打开 cmake 文件继续修改项目。我是改用了 vs2019,毕竟宇宙第一 ide

4. 配置 cmake

使用 Qt 创建项目后 cmake 文件里已经添加了部分必要的命令,这里只需要进行简单的修改。

下面贴出我的 cmake 文件,其中有些路径需要替换成自己的

cmake_minimum_required(VERSION 3.5)

project(seg)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt5 COMPONENTS Widgets REQUIRED)

# 这里设置了两个路径,第一个是 Pytorch 官方说明里指定的,路径就是解压的 libtorch 里的对应路径
# 我还设置了一个 lib 的路径,为了方便后面使用
set(Torch_DIR "D:/Microsoft Visual Studio/VC/Tools/libtorch/share/cmake/Torch")
set(TORCH_LIB "D:/Microsoft Visual Studio/VC/Tools/libtorch/lib")
find_package(Torch REQUIRED)

if(ANDROID)
  add_library(seg SHARED
    main.cpp
    mainwindow.cpp
    mainwindow.h
    mainwindow.ui
  )
else()
  add_executable(seg
    main.cpp
    mainwindow.cpp
    mainwindow.h
    mainwindow.ui
  )
endif()

target_link_libraries(seg Qt5::Widgets "${TORCH_LIBRARIES}")
set_property(TARGET seg PROPERTY CXX_STANDARD 11)

if(MSVC)
    file(COPY ${TORCH_LIB}/c10.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR} FOLLOW_SYMLINK_CHAIN)
    file(COPY ${TORCH_LIB}/torch_cpu.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR} FOLLOW_SYMLINK_CHAIN)
    file(COPY ${TORCH_LIB}/fbgemm.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR} FOLLOW_SYMLINK_CHAIN)
    file(COPY ${TORCH_LIB}/asmjit.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR} FOLLOW_SYMLINK_CHAIN)
endif()

最后几行是为了解决缺少 dll 文件报错的问题:

Win10 + VS2019 + Qt5 + Pytorch C++ cmake 基本配置

所以我添加了一些复制文件的命令,将这些 dll 文件复制到生成的 exe 文件夹下。

也可以直接将 libtorch/lib 文件夹下所有的 dll 文件复制到你的 exe 文件夹中,因为你也不知道会缺多少。

此外也可以将 lib 文件夹的路径添加到环境变量中。选择自己喜欢的方式就行。

在 vs2019 中打开 CMakeSettings.json 可以看到其他配置信息,根据自己的需要添加修改就行。

Win10 + VS2019 + Qt5 + Pytorch C++ cmake 基本配置
配置完成后 Ctrl + S 就可以生成了
Win10 + VS2019 + Qt5 + Pytorch C++ cmake 基本配置

5. 测试

接下来用一段 C++ 代码来测试是否成功。
把之前转换的 Pytorch 模型放到 exe 文件夹下。

#include "mainwindow.h"
#include <QApplication>
#include <iostream>

#undef slots
#include <torch/torch.h>
#include <torch/script.h>
#define slots Q_SLOTS

using namespace std;

int main(int argc, char* argv[])
{
    torch::Tensor tensor = torch::eye(3);
    std::cout << tensor << std::endl;
    
    torch::jit::script::Module module;
    module = torch::jit::load("model.pt");
    cout << "Succeed in loading model" << endl;
    
    system("PAUSE");
}

代码中有一段 #undef,添加这一部分是因为 qt 似乎和 libtorch 间有冲突,具体原因也不知道,至少加上这一段就能解决,会不会产生其他问题以后才知道。

然后就可以编译、生成了,编译的时候会出现很多警告,应该是 #undef 导致的,可以忽略。

Win10 + VS2019 + Qt5 + Pytorch C++ cmake 基本配置
这是全部完成后我的文件夹里的文件

Win10 + VS2019 + Qt5 + Pytorch C++ cmake 基本配置
这是运行结果

Win10 + VS2019 + Qt5 + Pytorch C++ cmake 基本配置
所有的准备操作到这里就结束了,后面就可以开始写 qt 界面了,预知后事是如何,且听下回分解。