Qt — это мощная среда для создания кроссплатформенных приложений с графическим интерфейсом. Для сценариев производственного развертывания вам необходимо интегрировать модели, разработанные в среде машинного обучения PyTorch, в ваш C++ QT. Чтобы загрузить модель PyTorch в C++, вам необходимо преобразовать модель в формат сценария torch. Вы можете найти подробные инструкции по преобразованию моделей Pytorch в скрипт torch здесь.
Скачать библиотеку libtorch
Перейдите на официальный сайт PyTorch ссылка и выберите соответствующую версию libtorch в зависимости от установленной ОС и версии Cuda.
Окна
https://download.pytorch.org/libtorch/cu111/libtorch-win-shared-with-deps-1.8.1%2Bcu111.zip
линукс
Download here (Pre-cxx11 ABI): https://download.pytorch.org/libtorch/cu111/libtorch-shared-with-deps-1.8.1%2Bcu111.zip Download here (cxx11 ABI): https://download.pytorch.org/libtorch/cu111/libtorch-cxx11-abi-shared-with-deps-1.8.1%2Bcu111.zip
Добавьте libtorch в проект qt
Это самое важное, но и более хлопотное. Во-первых, откройте файл проекта QT «.pro» и добавьте каталог заголовочных файлов libtorch (include) и каталог файлов библиотек (lib). Вам нужно добавить компилятор и флаги компоновки на основе платформы ОС, иначе libtorch не будет связываться с torch_cuda и в итоге «torch::cuda::is_available()» вернет 0. Libtorch рекомендует использовать CMAKE в качестве инструмента сборки, но вы можете добиться того же с помощью QMAKE для QT, но следует быть осторожным с флагами.
CONFIG += c++11 #Include the headers INCLUDEPATH += $$PYTORCH_DIR/include/torch/csrc/api/include \ $$quote($$CUDA_DIR/include) #compiler and linker flags unix { QMAKE_LFLAGS += -Wl,--no-as-needed } win32 { QMAKE_LFLAGS += -INCLUDE:?warp_size@cuda@at@@YAHXZ QMAKE_LFLAGS += -INCLUDE:?searchsorted_cuda@native@at@@YA?AVTensor@2@AEBV32@0_N1@Z QMAKE_LFLAGS += /machine:x64 } # linking with libs win32 { LIBS += $$quote($$PYTORCH_DIR\lib\*.lib) LIBS += -L$$quote($$PYTORCH_DIR\lib) LIBS += $$quote($$CUDA_DIR\lib\x64\*.lib) LIBS += -L$$quote($$CUDA_DIR\v11.1\bin) } unix { LIBS += -L$$PYTORCH_DIR/lib -ltorch_cpu -ltorch -lc10 -ltorch_cuda -lc10_cuda -lcaffe2_observers \ -lcaffe2_nvrtc -lcaffe2_detectron_ops_gpu \ -lnvrtc-builtins -lprocess_group_agent -lshm \ -ltensorpipe_agent -ltorch -ltorch_cuda_cpp -ltorch_cuda_cu -ltorch_global_deps }
Создайте приложение QT с помощью LibTorch
Следующим шагом является сборка исходного кода проекта QT, и вы получите ошибки, связанные с ошибкой компиляции конфликтов слотов, если ваше приложение основано на виджетах QT. Это связано с конфликтами ключевых слов slots между библиотеками QT и libtorch, и вы можете избежать этого, добавив файлы заголовков libtorch в начало исходного кода, как показано ниже.
#undef slots #include "torch/torch.h" #include "torch/jit.h" #include "torch/nn.h" #include "torch/script.h" #define slots Q_SLOTS #include "mainwindow.h" #include "ui_mainwindow.h" #include <QList>
Проверьте Libtorch, загруженный с возможностью Cuda, и его конфигурацию.
qDebug() << "Cuda Device Count" << torch::cuda::device_count(); qDebug() << "cudnn_is_available" << torch::cuda::cudnn_is_available(); qDebug() << "cuda::is_available" << torch::cuda::is_available(); qDebug() << "cuda::show_config" << torch::show_config().c_str();
После выполнения приложения вы получите журналы, как показано ниже, если существует какой-либо графический процессор.
Cuda Device Count 1 cudnn_is_available true cuda::is_available true cuda::show_config PyTorch built with: - C++ Version: 199711 - MSVC 192829913 - Intel(R) Math Kernel Library Version 2020.0.2 Product Build 20200624 for Intel(R) 64 architecture applications - Intel(R) MKL-DNN v1.7.0 (Git Hash 7aed236906b1f7a05c0917e5257a1af05e9ff683) - OpenMP 2019 - CPU capability usage: AVX2 - CUDA Runtime 11.1 - NVCC architecture flags: -gencode;arch=compute_37,code=sm_37;-gencode;arch=compute_50,code=sm_50;-gencode;arch=compute_60,code=sm_60;-gencode;arch=compute_61,code=sm_61;-gencode;arch=compute_70,code=sm_70;-gencode;arch=compute_75,code=sm_75;-gencode;arch=compute_80,code=sm_80;-gencode;arch=compute_86,code=sm_86;-gencode;arch=compute_37,code=compute_37 - CuDNN 8.0.5 - Magma 2.5.4 - Build settings: BLAS_INFO=mkl, BUILD_TYPE=Release, CUDA_VERSION=11.1, CUDNN_VERSION=8.0.5, CXX_COMPILER=C:/w/b/windows/tmp_bin/sccache-cl.exe, CXX_FLAGS=/DWIN32 /D_WINDOWS /GR /EHsc /w /bigobj -DUSE_PTHREADPOOL -openmp:experimental -DNDEBUG -DUSE_FBGEMM -DUSE_XNNPACK, LAPACK_INFO=mkl, PERF_WITH_AVX=1, PERF_WITH_AVX2=1, PERF_WITH_AVX512=1, TORCH_VERSION=1.8.1, USE_CUDA=ON, USE_CUDNN=ON, USE_EXCEPTION_PTR=1, USE_GFLAGS=OFF, USE_GLOG=OFF, USE_MKL=ON, USE_MKLDNN=ON, USE_MPI=OFF, USE_NCCL=OFF, USE_NNPACK=OFF, USE_OPENMP=ON,
Примечание. Необходимо создать приложение QT с помощью MSVC, поскольку libtorch не поддерживает MinGW в Windows.
Загрузите модель torchscript и запустите вывод
Загрузите модель скрипта факела в модуль факела библиотеки.
torch::jit::script::Module aLibTorchModule = torch::jit::load("torch script model path");
Выберите устройство GPU, если оно доступно, в противном случае выберите устройство CPU.
torch::DeviceType aDeviceType; if (torch::cuda::is_available()) { aDeviceType= torch::kCUDA; } else { aDeviceType= torch::kCPU; } torch::Device aTorchDevice = torch::Device(aDeviceType);
Переместите загруженный модуль на выбранное устройство, в нашем случае это GPU
aLibTorchModule.to(aTorchDevice);
Теперь вы можете выполнить вывод в модуле libtorch, минуя правильный ввод в модель. Lib torch предоставляет функцию преобразования во входной тензор, если у вас есть открытый объект изображения cv::Mat.
auto input_tensor = torch::from_blob( data, {1, Height, Width, 3}); // here data should opencv CV::MAT
Иногда вам может потребоваться предварительно обработать входные данные на основе ожиданий модели, а следование функции факела lib позволяет вам изменить порядок измерения входного тенора и нормализовать входные данные, прежде чем приступить к фактическому выводу.
input_tensor = input_tensor.permute({0, 3, 1, 2}); std::vector<double> norm_mean = {0.485, 0.456, 0.406}; std::vector<double> norm_std = {0.229, 0.224, 0.225}; input_tensor = torch::data::transforms::Normalize<>(norm_mean, norm_std)(input_tensor);
Наконец, выполните вывод в модуле libtorch, где модель загружается в начале. Метод Libtorch Forward возвращает результаты в виде тензорных объектов, и вы можете получать результаты и манипулировать ими в соответствии с вашими потребностями. Убедитесь, что вы должны переместить свой входной тензор в GPU перед обработкой вывода, если ваша модель загружена в GPU, иначе вы получите ошибку.
input_tensor = input_tensor.to(aTorchDevice); torch::Tensor out_tensor = aLibTorchModule.forward({input_tensor}).toTensor();