我们有一个使用 LibTorch 1.5.0 的工作库,使用 CUDA 10.0 构建,可以按预期运行。
出于各种与 PyTorch 无关的原因,我们正在努力升级到 CUDA 10.2。我们注意到,当我们在新编译的 LibTorch 上运行 LibTorch 推理时(编译时完全相同,除了更改为 CUDA 10.2),运行时间大约慢了 20 倍。我们还使用预编译的二进制文件对其进行了检查。
这是在 3 台不同的机器上使用 3 个不同的 GPU(Tesla T4、GTX980 和 P1000)进行测试的,并且在 CUDA 10.2(Windows 10 和 Ubuntu 16.04 上)上都给出了一致的 ~20 倍慢,所有这些都使用最新的驱动程序和 3 个不同的火炬脚本(相同架构)
我已将代码简化为极少,无需 Torch 以外的外部依赖项
int main(int argc, char** argv)
{
// Initialize CUDA device 0
cudaSetDevice(0);
std::string networkPath = DEFAULT_TORCH_SCRIPT;
if (argc > 1)
{
networkPath = argv[1];
}
auto jitModule = std::make_shared<torch::jit::Module>(torch::jit::load(networkPath, torch::kCUDA));
if (jitModule == nullptr)
{
std::cerr << "Failed creating module" << std::endl;
return EXIT_FAILURE;
}
// Meaningless data, just something to pass to the module to run on
// PATCH_HEIGHT & WIDTH are defined as 256
uint8_t* data = new uint8_t[PATCH_HEIGHT * PATCH_WIDTH * 3];
memset(data, 0, PATCH_HEIGHT * PATCH_WIDTH * 3);
auto stream = at::cuda::getStreamFromPool(true, 0);
bool res = infer(jitModule, stream, data, PATCH_WIDTH, PATCH_HEIGHT);
std::cout << "Warmed up" << std::endl;
res = infer(jitModule, stream, data, PATCH_WIDTH, PATCH_HEIGHT);
delete[] data;
return 0;
}
// Inference function
bool infer(std::shared_ptr<JitModule>& jitModule, at::cuda::CUDAStream& stream, const uint8_t* inputData, int width, int height)
{
std::vector<torch::jit::IValue> tensorInput;
// This function simply uses cudaMemcpy to copy to device and create a torch::Tensor from that data
// I can paste it if it's relevant but didn't now to keep as clean as possible
if (!prepareInput(inputData, width, height, tensorInput, stream))
{
return false;
}
// Reduce memory usage, without gradients
torch::NoGradGuard noGrad;
{
at::cuda::CUDAStreamGuard streamGuard(stream);
auto totalTimeStart = std::chrono::high_resolution_clock::now();
jitModule->forward(tensorInput);
// The synchronize here is just for timing sake, not use in production
cudaStreamSynchronize(stream.stream());
auto totalTimeStop = std::chrono::high_resolution_clock::now();
printf("forward sync time = %.3f milliseconds\n",
std::chrono::duration<double, std::milli>(totalTimeStop - totalTimeStart).count());
}
return true;
}
当使用使用 CUDA 10.0 编译的 Torch 编译它时,我们得到一个运行时18 ms
,当我们使用使用 CUDA 10.2 编译的 Torch 运行它时,我们得到一个运行时430 ms
对此有什么想法吗?
这个问题也发布在PyTorch 论坛上。
GitHub 上的问题
更新
我使用两个 CUDA 分析了这个小程序
似乎两者都使用非常不同的内核
conv2d_grouped_direct_kernel
在我的 P1000 上,96.5% 的 10.2 计算需要大约 60-100 毫秒
10.0 运行中的顶级内核在哪里
47.1% - cudnn::detail::implicit_convolve_sgemm (~1.5 ms)
23.1% - maxwell_scudnn_winograd_128x128_ldg1_ldg4_tile148n_nt (~0.4 ms)
8.5% - maxwell_scudnn_128x32_relu_small_nn (~0.4ms)
所以很容易看出时差是从哪里来的。现在的问题是,为什么。