当前位置:   article > 正文

libtorch显存管理示例_c10::cuda::cudacachingallocator::emptycache()

c10::cuda::cudacachingallocator::emptycache()

在使用libtorch进行部署时,会面临显存不够用的情况。因此需要对显存的利用进行管理,对此研究libtorch的api,尝试进行显存管理。libtorch运行程序时,显存占用可以分为3块:模型参数占用显存、输入输出tensor占用显存、模型forword过程临时变量占用显存。

使用cudaFree(tensor.data_ptr())可以释放掉tensor所占用的显存,也可以使用该函数释放掉模型参数所占用的显存。使用CUDACachingAllocator::emptyCache函数可以释放掉模型在forword过程中的一些显存。

为了探究模型部署时各阶段的显存占用和管理,进行以下代码测试。

1、环境配置

进行显存管理时,需要配置cuda,cuda配置可以参考图1。此外,还需要在链接器-》输入-》附加依赖项中,配置cudnn.lib;cublas.lib;cudart.lib;。

图1 CUDA配置

libtorch的配置可以参考pytorch 4 libtorch配置使用实录(支持cuda的调用)_万里鹏程转瞬至的博客-CSDN博客

 2、库导入和基本函数实现

下列代码主要实现cuda和libtorch的导入,和cuda使用查询的函数

  1. #include <torch/script.h>
  2. #include <torch/torch.h>
  3. #include <c10/cuda/CUDAStream.h>
  4. #include <ATen/cuda/CUDAEvent.h>
  5. #include <iostream>
  6. #include <memory>
  7. #include <string>
  8. #include <cuda_runtime_api.h>
  9. using namespace std;
  10. static void print_cuda_use( )
  11. {
  12. size_t free_byte;
  13. size_t total_byte;
  14. cudaError_t cuda_status = cudaMemGetInfo(&free_byte, &total_byte);
  15. if (cudaSuccess != cuda_status) {
  16. printf("Error: cudaMemGetInfo fails, %s \n", cudaGetErrorString(cuda_status));
  17. exit(1);
  18. }
  19. double free_db = (double)free_byte;
  20. double total_db = (double)total_byte;
  21. double used_db_1 = (total_db - free_db) / 1024.0 / 1024.0;
  22. std::cout << "Now used GPU memory " << used_db_1 << " MB\n";
  23. }

3、libtorch过程显存管理

代码中的d_in_out.pt参考自以下链接,但略有不同(模型参数更多了,博主把模型的参数增加了100倍,其实就是把每一个kernel的filer_num增大了)pytorch 6 libtorch部署多输入输出模型(支持batch)_万里鹏程转瞬至的博客-CSDN博客_pytorch多输入1、pytorch下构建多输入输出模型下面构建一个简洁的多输入输出模型import torchimport torch.nn as nnimport torch.nn.functional as Fclass MyModel(nn.Module): def __init__(self): super(MyModel, self).__init__() self.conv1 = nn.Conv2d(6, 16, kernel_size=1, stridehttps://blog.csdn.net/a486259/article/details/121680988

 代码中的注释详细说明了每一个操作是否有效和其影响 

  1. int main() {
  2. string path = "d_in_out.pt";
  3. //设置不需要存储梯度信息
  4. at::NoGradGuard nograd;
  5. int gpu_id = 0;
  6. //加载模型
  7. torch::jit::Module model = torch::jit::load(path);
  8. model.to(at::kCUDA);
  9. model.eval();//设置评价模式
  10. std::cout << "加载模型后的显存占用\n";
  11. print_cuda_use();
  12. //构建双输入数据
  13. //对于单输入模型只需要push_back一次
  14. at::Tensor x1_tensor = torch::ones({ 1,3,512,512 }).to(at::kCUDA);
  15. at::Tensor x2_tensor = torch::ones({ 1,3,512,512 }).to(at::kCUDA);
  16. at::Tensor result1,result2;
  17. std::cout << "\n初始化tensor的显存占用\n";
  18. print_cuda_use();
  19. std::cout << "\n循环运行5次\n";
  20. for (int i = 0;i < 5;i++) {
  21. //result=model.forward({ x1_tensor,x2_tensor }).toTensor();//one out
  22. auto out = model.forward({ x1_tensor,x2_tensor });
  23. auto tpl = out.toTuple();//out.toTensorList();
  24. result1 = tpl->elements()[0].toTensor();
  25. result2 = tpl->elements()[1].toTensor();
  26. print_cuda_use();
  27. }
  28. std::cout << "\n释放tensor所占用的显存(帮助不大)\n";
  29. cudaFree(x1_tensor.data_ptr());
  30. cudaFree(x1_tensor.data_ptr());
  31. cudaFree(result1.data_ptr());
  32. cudaFree(result2.data_ptr());
  33. print_cuda_use();
  34. std::cout << "\nCUDACachingAllocator::emptyCache (有点效果)\n";
  35. c10::cuda::CUDACachingAllocator::emptyCache();
  36. print_cuda_use();
  37. std::cout << "\n释放模型参数占用的显存(无意义)\n";
  38. for (auto p : model.parameters())
  39. cudaFree(p.data_ptr());//接下来不能使用cuda,导致model.to(at::kCUDA);报错
  40. print_cuda_use();
  41. //torch::jit::Module::Module::freeze(model);
  42. std::cout << "\n调用模型的析构函数(无效)\n";
  43. model.~Module();//对显存变化没有实际帮助
  44. print_cuda_use();
  45. std::cout << "\n重置cuda状态(无效)\n";
  46. c10::cuda::CUDACachingAllocator::init(gpu_id);
  47. c10::cuda::CUDACachingAllocator::resetAccumulatedStats(gpu_id);//对显存变化没有实际帮助
  48. c10::cuda::CUDACachingAllocator::resetPeakStats(gpu_id);
  49. print_cuda_use();
  50. std::cout << "\ncudaDeviceReset(有效,会导致后续模型无法使用cuda)\n";
  51. //需要配置cuda
  52. cudaDeviceReset();//完全释放GPU资源 接下来不能使用cuda,导致model.to(at::kCUDA);报错 除非能重新初始化libtorch的cuda环境
  53. print_cuda_use();
  54. torch::cuda::synchronize();
  55. model = torch::jit::load(path);
  56. model.to(at::kCUDA);
  57. print_cuda_use();
  58. return 0;
  59. }

上述代码的执行结果如下图所示。 

最终结果表明,libtorch是无法有效的释放显存。需要需要做到显存的极致管理,还得使用onnxruntime或tensorrt进行部署。

onnxruntime的部署可以参考pytorch 17 onnx多输入多输出模型在python与C++下用OnnxRuntime部署_万里鹏程转瞬至的博客-CSDN博客_onnx多输入pytorch模型在转换成onnx模型后可以明显加速,此外模型在进行openvino部署时也需要将pytorch模型转换为onnx格式。为此,以多输入多输出模型为例,记录一下模型转换及python下onnxruntime调用过程。并实现C++下多输入多输出模型的Onnxruntime的调用。一 、python下模型转onnx与测试1.1、构建pytorch多输入多输出模型import torchimport torch.nn as nnimport torch.nn.functional https://hpg123.blog.csdn.net/article/details/122473889tensorrt的部署可以参考pytorch 29 onnx多输入多输出模型(动态尺寸)转TensorRT模型并在python与C++下用TensorRT进行部署_万里鹏程转瞬至的博客-CSDN博客_onnx模型转tensorrt实现将多输入多输出的onnx模型转TensorRT的格式,并用TensorRT的python api进行调用,最后实现C++的调用,python结果与C++结果一模一样。在此过程中实现了,动态尺寸,也就是可以在运行是按照数据情况动态调整模型的输入数据的格式。在这里以pytorch的多输入多输出模型为例,从模型构建到转化为onnx动态size、tensorrt安装、onnx转tensorRT动态size、tensorRT模型pytthon调用、tensorRT C++项目配置,最终到tensorRT模型C++https://hpg123.blog.csdn.net/article/details/125191219

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/127393
推荐阅读
相关标签
  

闽ICP备14008679号