1 TensorRT的性能衡量标准

使用 TensorRT 进行模型优化工作之前,必须确定应该测量什么。没有衡量标准,就不可能取得可靠的进展或衡量是否取得了成功

Latency

第一个衡量标准是从输入数据经过网络然后输出的时间,这个时间称为延迟(Latency)。在一些项目中,较低的模型推理延迟是非常重要的指标,较低的延迟意味着低的用户等待时间,可以改善用户体验。

Throughput

另一个指标是在固定的时间单位内可以完成多少推理。这是网络的吞吐量。吞吐量越高越好。更高的吞吐量表明更有效地利用固定计算资源。对于批量处理,所花费的总时间将由网络的吞吐量决定。

2 TensorRT中计算推理时间

第一个常规方案,我们可以使用std::chrono统计推理时间。

另一个是使用使用CUDA的API来计算模型推理延迟,主要使用的是CUDA Events相关的API。我们可以在推理之前记录一个事件,然后在推理之后记录一个事件,然后通过cudaEventElapsedTime统计两个事件之间经过的时间,时间单位为毫秒(ms)。

2.1 std::chrono

第一个比较常规的方案就是使用CPU的耗时,比如使用C++11的std::chrono对函数片段进行计时,比如

#include <chrono>

auto startTime = std::chrono::high_resolution_clock::now();

context->enqueueV2(&buffers[0], stream, nullptr);
cudaStreamSynchronize(stream);

auto endTime = std::chrono::high_resolution_clock::now();
float totalTime = std::chrono::duration<float, std::milli>(endTime - startTime).count();

如果设备上一次只发生一个推理,那么这可能是一种简单的方法来分析各种操作所花费的时间。但是推理往往是异步的,因此这种方式统计的计时不一定准确。

2.2 CUDA Events

2.2.1 创建和销毁事件

创建事件

cudaError_t cudaEventCreate(cudaEvent_t* event);

销毁事件

cudaError_t cudaEventDestroy(cudaEvent_t event);

在销毁事件时,如果与其相关的操作没有完成,则会在操作完成之后自动释放资源。

2.2.2 记录事件和计算时间

Events标记了stream执行过程中的一个点,我们就可以检查正在执行的stream中的操作是否到达该点,我们可以把event当成一个操作插入到stream中的众多操作中,当执行到该操作时,所做工作就是设置CPU的一个flag来标记表示完成。下面函数将event关联到指定stream。

cudaError_t cudaEventRecord(cudaEvent_t event, cudaStream_t stream = 0);

等待event会阻塞调用host线程,同步操作,调用下面的函数:

cudaError_t cudaEventSynchronize(cudaEvent_t event);

我们同时可以使用下面的API来测试event是否完成,该函数不会阻塞host:

cudaError_t cudaEventQuery(cudaEvent_t event);

然后使用以下api计算两个event之间的时间间隔:

cudaError_t cudaEventElapsedTime(float* ms, cudaEvent_t start, cudaEvent_t stop);

该函数返回start和end两个事件的时间间隔,单位是毫秒。

start和stop事件不必关联到同一个stream上,但是要注意,如果二者任意一个关联到了non-NULL stream上,时间间隔可能要比期望的大。这是因为cudaEventRecord是异步发生的,我们没办法保证度量出来的时间恰好就是两个event之间,所以只是想要gpu工作的时间间隔,则stop和strat都关联到默认stream就好了。

2.2.3 计算推理事件的示例代码

使用CUDA Event事件计算推理时间的示例代码如下:

// 创建两个事件,一个开始事件,一个结束事件
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);

// 在默认的stream记录开始事件
cudaEventRecord(start);

// 推理部分代码

// 推理完成后,记录结束事件
cudaEventRecord(stop);

// 等待结束事件完成
cudaEventSynchronize(stop);

// 计算间隔时间
float time;
cudaEventElapsedTime(&time, start, stop);

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

我们可以在TensorRT推理部分使用上述代码统计模型推理时间。

参考链接