前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TensorRT | 在多个GPU中指定推理设备

TensorRT | 在多个GPU中指定推理设备

作者头像
OpenCV学堂
发布2023-08-22 13:41:17
9350
发布2023-08-22 13:41:17
举报
文章被收录于专栏:贾志刚-OpenCV学堂
前言

说实话,之前我在笔记本上都一直都是只有一块N卡,所以没有过多关注过这个问题。然而昨天有个人问我,TensorRT怎么在多个GPU中指定模型推理GPU设备?我查了一下,发现官方有几个不同的解决方案,个人总结了一下,主要的做法有两种。

01

配置环境变量支持

该方法的好处是不需要修改代码,通过配置环境变量就可以实现指定的GPU运行,缺点是缺乏灵活性,特别是想切换不同GPU实现模型推理的时候,这个方法就弊端就比较明显。

CUDA编程中支持的指定GPU设备的环境变量为:

代码语言:javascript
复制
CUDA_VISIBLE_DEVICES

通过该系统的环境变量可以设置指定的单个GPU编号或者多个GPU编号合集,然后在程序测试与调试环境中使用。通过这种方式指定GPU编号执行模型推理,就无需修改代码,实现在单一指定的GPU上运行TensorRT推理程序。

02

代码指定GPU设备执行

一台机器上可能有多个GPU设备,通过CUDA编程可以查询机器上所有的GPU设备,查询这些设备的属性以及决定使用哪个GPU设备作为当前设备。

代码语言:javascript
复制
cudaGetDeviceCount

该函数可以查询到当前机器上GPU设备数目,然后遍历查询每个GPU设备的属性。官方教程给出的代码如下:

代码语言:javascript
复制
// 查询设备数目
int deviceCount;
cudaGetDeviceCount(&deviceCount);

// 遍历设备编号信息
int device;
for (device = 0; device < deviceCount; ++device) {
    cudaDeviceProp deviceProp;
    cudaGetDeviceProperties(&deviceProp, device);
    printf("Device %d has compute capability %d.%d.\n",
        device, deviceProp.major, deviceProp.minor);
}

根据查询的设备数目,GPU编号从0开始,默认情况下当前使用的设备就是编号为0的GPU设备,通过函数cudaSetDevice()可以修改运行时使用GPU设备,在初始化TensorRT之前,先通过cudaSetDevice()函数修改默认的当前设备,然后再初始化就可以把TensorRT的模型绑定到指定编号的GPU设备上推理。以我的笔记本上为例,设置当前的GPU设备,然后初始化TensorRT代码如下:

代码语言:javascript
复制
// 设置当前设备为GPU 0
cudaSetDevice(0);// 初始化TensorRT
this->runtime = createInferRuntime(gLogger);
assert(this->runtime != nullptr);
this->engine = runtime->deserializeCudaEngine(trtModelStream, size);
assert(this->engine != nullptr);
this->context = engine->createExecutionContext();
assert(this->context != nullptr);
delete[] trtModelStream;

// do more thing here// insert query input and output layers information
// 创建GPU显存输入/输出缓冲区
std::cout << " input/outpu : " << engine->getNbBindings() << std::endl;
cudaMalloc(&buffers[input_index], this->input_h * this->input_w * 3 * sizeof(float));
cudaMalloc(&buffers[2], this->output_h *this->output_w * sizeof(float));
cudaMalloc(&buffers[1], 32 *25600 * sizeof(float));

// 创建临时缓存输出
prob.resize(output_h * output_w);
mprob.resize(32 * 25600);

// 创建cuda流
cudaStreamCreate(&stream);

在多个GPU设备上执行多个模型推理的初始化代码如下:

代码语言:javascript
复制
// 初始化时间标记
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, 0);

// 查询设备数目
int deviceCount;
cudaGetDeviceCount(&deviceCount);

// 遍历设备编号信息
int device;
for (device = 0; device < deviceCount; ++device) {
    cudaDeviceProp deviceProp;
    cudaGetDeviceProperties(&deviceProp, device);
    printf("Device %d has compute capability %d.%d.\n",
        device, deviceProp.major, deviceProp.minor);
}

// Set GPU 0 as current
cudaSetDevice(0);            
cudaStream_t s0;
cudaStreamCreate(&s0);
void* p0[1];
size_t size = 1024 * sizeof(float);
cudaMalloc(p0[0], size);
// initialization TensorRT here on GPU 0 

// Set GPU 1 as current
cudaSetDevice(1);            
cudaStream_t s1;
cudaStreamCreate(&s1);
// initialization TensorRT here on GPU 1

// 计算执行时间
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
float elapsedTime;
cudaEventElapsedTime(&elapsedTime, start, stop);
printf("time to consume: %3.1f ms \n", elapsedTime);

// 销毁
cudaEventDestroy(start);
cudaEventDestroy(stop);

关于延时加载

TensorRT8.6支持CUDA Lazy Loading(延时加载),开发者文档上说这种方式可以有效降低GPU显存与内存使用,加速初始化,节省模型初始化时间,可以通过环境变量配置实现延时加载支持,相关环境变量为:

代码语言:javascript
复制
CUDA_MODULE_LOADING=LAZY

参考资料:

代码语言:javascript
复制
https://developer.nvidia.com/blog/cuda-pro-tip-control-gpu-visibility-cuda_visible_devices/
https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#multi-device-system

掌握TensorRT8.6 C++如何部署图像分类,对象检测,实例分割,语义分割主流模型,自定义脚本一键INT8量化模型,使用OpenCV CUDA加速图像预处理等各种工程化部署推理技巧,实现推理部署的工程化封装支持

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 OpenCV学堂 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档