TensorRT是一個高性能的深度學習推理(Inference)優化器,可以為深度學習應用提供低延遲、高吞吐率的部署推理。TensorRT可用于對超大規模數據中心、嵌入式平臺或自動駕駛平臺進行推理加速。TensorRT現已能支持TensorFlow、Caffe、Mxnet、Pytorch等幾乎所有的深度學習框架,將TensorRT和NVIDIA的GPU結合起來,能在幾乎所有的框架中進行快速和高效的部署推理。
創新互聯公司專注于安陸網站建設服務及定制,我們擁有豐富的企業做網站經驗。 熱誠為您提供安陸營銷型網站建設,安陸網站制作、安陸網頁設計、安陸網站官網定制、微信小程序服務,打造安陸網絡公司原創品牌,更為您提供安陸網站排名全網營銷落地服務。在平時的工作與學習中也都嘗試過使用Libtorch和onnxruntime的方式部署過深度學習模型。但這兩款多多少少存在著內存與顯存占用的問題,并且無法完全釋放。(下文的部署方式不僅簡單并且在前向推理過程所需的顯存更低,并且在推理結束后可以隨時完全釋放顯存)。
二?安裝: 1.安裝環境win10
vs2019
cuda10.2
pytorch1.9
只要其中的pytorch,cuda版本與后續的Tensorrt版本對應即可
2.模型轉化首先需要將pytorch的.pth模型轉化為onnx的模型(為了后邊的方便,目前講解的方式都是單卡的方式)。轉化方式很簡單pytorch已經提供,網上也有許多講解這個函數的博客。此處直接上代碼:(必須確定.pth模型是可以正常使用的否則后面轉化的模型也都無法使用)。
def Convert_ONNX(model,input_size):
model.eval()
dummy_input = torch.randn(input_size).cuda()
torch.onnx.export(model, # model being run
dummy_input, # model input (or a tuple for multiple inputs)
"PytorchtoOnnx.onnx", # where to save the model
# dynamic_axes = {'inputs':{0:"batch"}}, #表示batch這個維度可變的 (有這個參數可以關閉不用設置)會麻煩很多
verbose = True,
export_params=True, # store the trained parameter weights inside the model file
input_names = ['inputs'], # the model's input names
output_names = ['modelOutput']) # the model's output names
print("end")
3.將onnx模型通過tensorrt自帶工具完成轉化首先去官網https://developer.nvidia.com/nvidia-tensorrt-download下載與自己pytorch版本和cuda版本適應的tensorrt版本。
下載完成后打開里面的bin文件夾,里面存在著一個trtexec.exe。利用以下代碼將之前獲得的onnx文件轉化為trt文件。這里講解最簡單的方式,因為trtexec.exe有許多可以優化的功能,最終都會影響模型的精度與速度。在命令行中輸入如下指令。
trtexec.exe --onnx=PytorchtoOnnx.onnx --saveEngine=TrtModel.trt --explicitBatch --workspace=4096
這里模型轉化可能需要一點時間,完成轉化后會得到TrtMedel.trt模型。那么準備工作也就完成了。接下來開始C++部署。
三?部署: 1.打開VS新建空項目 2.配置環境在VC++目錄---包含目錄中添加cuda路徑和tensorrt路徑(此處用的是相對路徑,你也可以用絕對路徑)其中$(CUDA_PATH)\include是指cuda中的include文件,我的在C:\Program?Files\NVIDIA?GPU?Computing?Toolkit\CUDA\v10.2\include
在VC++目錄---庫目錄中添加
還需要將字符集改成:使用多字節字符集。否則會報C2664?“HMODULE?LoadLibraryW(LPCWSTR)”:?無法將參數?1?從“const?_Elem?*”轉換為“LPCWSTR”??的錯誤。
3.部署代碼必須新建一個logger.cpp的文件。里面寫入如下代碼。
#include "logger.h"
#include "ErrorRecorder.h"
#include "logging.h"
SampleErrorRecorder gRecorder;
namespace sample
{
Logger gLogger{Logger::Severity::kINFO};
LogStreamConsumer gLogVerbose{LOG_VERBOSE(gLogger)};
LogStreamConsumer gLogInfo{LOG_INFO(gLogger)};
LogStreamConsumer gLogWarning{LOG_WARN(gLogger)};
LogStreamConsumer gLogError{LOG_ERROR(gLogger)};
LogStreamConsumer gLogFatal{LOG_FATAL(gLogger)};
void setReportableSeverity(Logger::Severity severity)
{
gLogger.setReportableSeverity(severity);
gLogVerbose.setReportableSeverity(severity);
gLogInfo.setReportableSeverity(severity);
gLogWarning.setReportableSeverity(severity);
gLogError.setReportableSeverity(severity);
gLogFatal.setReportableSeverity(severity);
}
} // namespace sample
再新建一個test.cpp進行測試。測試代碼如下:(下面是一個unet的分割模型,并且前面的預處理例如標準化等都在外面完成了。下面只涉及到推理部分)。
#include#include
#includeusing namespace std;
#include#include "NvInfer.h"
#include "argsParser.h"
#include "logger.h"
#include "common.h"
#include "NvOnnxParser.h"
#include "buffers.h"
using namespace nvinfer1;
bool read_TRT_File(const std::string& engineFile, ICudaEngine*& engine)
{
fstream file;
file.open(engineFile, ios::binary | ios::in);
file.seekg(0, ios::end); // 定位到 fileObject 的末尾
int length = file.tellg();
file.seekg(0, std::ios::beg); // 定位到 fileObject 的開頭
unique_ptrdata(new char[length]);
file.read(data.get(), length);
file.close();
nvinfer1::IRuntime* trtRuntime = createInferRuntime(sample::gLogger.getTRTLogger());
engine = trtRuntime->deserializeCudaEngine(data.get(), length, nullptr);
assert(engine != nullptr);
std::cout<< "The engine in TensorRT.cpp is not nullptr"<< std::endl;
//trtModelStream = engine->serialize();
trtRuntime->destroy();
return true;
}
void doInference(IExecutionContext& context, float* input, float* output,int InputSize, int OutPutSize,int BatchSize)
{
const char* INPUT_BLOB_NAME = "inputs";
const char* OUTPUT_BLOB_NAME = "modelOutput";
const ICudaEngine& engine = context.getEngine();
// input and output buffer pointers that we pass to the engine - the engine requires exactly IEngine::getNbBindings(),
// of these, but in this case we know that there is exactly one input and one output.
assert(engine.getNbBindings() == 2);
void* buffers[2];
// In order to bind the buffers, we need to know the names of the input and output tensors.
// note that indices are guaranteed to be less than IEngine::getNbBindings()
const int inputIndex = engine.getBindingIndex(INPUT_BLOB_NAME);
const int outputIndex = engine.getBindingIndex(OUTPUT_BLOB_NAME);
// DebugP(inputIndex); DebugP(outputIndex);
// create GPU buffers and a stream
CHECK(cudaMalloc(&buffers[inputIndex], InputSize * sizeof(float)));
CHECK(cudaMalloc(&buffers[outputIndex], OutPutSize * sizeof(float)));
cudaStream_t stream;
CHECK(cudaStreamCreate(&stream));
// DMA the input to the GPU, execute the batch asynchronously, and DMA it back:
CHECK(cudaMemcpyAsync(buffers[inputIndex], input, InputSize * sizeof(float), cudaMemcpyHostToDevice, stream));
context.enqueue(BatchSize, buffers, stream, nullptr);
CHECK(cudaMemcpyAsync(output, buffers[outputIndex], OutPutSize * sizeof(float), cudaMemcpyDeviceToHost, stream));
cudaStreamSynchronize(stream);
// release the stream and the buffers
cudaStreamDestroy(stream);
CHECK(cudaFree(buffers[inputIndex]));
CHECK(cudaFree(buffers[outputIndex]));
}
void runs(short* Data, int ImageCol, int ImageRow, int ImageLayer, unsigned char* Outputs)
{
int numall = ImageCol * ImageRow * ImageLayer;
float* PatchData = new float[numall];
Process(Data, ImageCol, ImageRow, ImageLayer, PatchData); //前處理
string eigineFile = "TrtMedel.trt";
ICudaEngine* engine = nullptr;
read_TRT_File(eigineFile, engine);
IExecutionContext* context = engine->createExecutionContext();
assert(context != nullptr);
float* out_image = new float[3 * numall];
int batchsize = 1;
int InputSize = 1 * 1 * numall;
int OutputSize = 1 * 3 * numall;
doInference(*context, PatchData, out_image, InputSize, OutputSize, batchsize);
EndProcess(out_image, 3, ImageCol, ImageRow, ImageLayer, Outputs); //后處理
context->destroy();
engine->destroy();
cudaDeviceReset();
delete[] out_image;
delete[] PatchData;
cout<<"柯西的筆"<
四?總結如上代碼可以即可以正常運行編譯。目前Tensorrt只支持20系以上顯卡,在10系顯卡也可以部署但是并沒有什么明顯的加速效果,但是顯存還是會比其他部署模塊低。
?如何涉及到整個項目完整在無CUDA環境中的部署,其實也很簡單。有需求的可以私信我。(也請關注柯西的筆公眾。
你是否還在尋找穩定的海外服務器提供商?創新互聯www.cdcxhl.cn海外機房具備T級流量清洗系統配攻擊溯源,準確流量調度確保服務器高可用性,企業級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧
名稱欄目:深度學習模型C++部署TensorRT-創新互聯
鏈接URL:http://vcdvsql.cn/article10/dsoego.html
成都網站建設公司_創新互聯,為您提供品牌網站設計、網站維護、網站導航、靜態網站、電子商務、建站公司
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯