TensorRT C++ 에서 엔진파일 로딩하여 추론하기

안녕하세요.
GPU를 MFC에서 사용하며 ONNX를 사용하려고 하다가
속도 이슈 때문에 TensorRT를 알아보고 있습니다.
Onnx파일을 파싱하여 인퍼런스하는 샘플을 보고
trtexec로 엔진 파일을 작성 하여 엔진파일을 이용해 c++에서 추론에 사용하고 싶습니다.
예제가 파이썬밖에 잘 없던데 혹시 아시는 분(혹은GPT) 계신가요?

  • 아래 답변은 OpenAI의 GPT-3.5(ChatGPT) 모델로 자동 생성한 것으로, 정확하지 않을 수 있습니다.
  • 잘못된 답변을 보셨다면 댓글로 첨삭 지도 부탁드립니다. :sweat_smile:

안녕하세요. TensorRT C++에서 엔진 파일을 로딩하여 추론하는 방법에 대해 설명드리겠습니다.

TensorRT C++에서 엔진 파일을 로딩하여 추론하는 방법은 다음과 같습니다.

  1. TensorRT 엔진 파일 생성하기

    • TensorRT 엔진 파일은 TensorRT Python API를 사용하여 생성할 수 있습니다.
    • TensorRT Python API를 사용하여 엔진 파일을 생성하는 방법은 다음과 같습니다.
    import tensorrt as trt
    
    # TensorRT 엔진 파일 생성을 위한 Builder 생성
    builder = trt.Builder(TRT_LOGGER)
    
    # ONNX 모델 파싱
    explicit_batch = 1 << (int)(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)
    network = builder.create_network(explicit_batch)
    parser = trt.OnnxParser(network, TRT_LOGGER)
    with open(onnx_model_path, 'rb') as model:
        parser.parse(model.read())
    
    # TensorRT 엔진 파일 생성
    engine = builder.build_cuda_engine(network)
    with open(engine_file_path, "wb") as f:
        f.write(engine.serialize())
    
  2. TensorRT 엔진 파일 로딩하기

    • TensorRT 엔진 파일을 로딩하기 위해서는 IRuntime 인터페이스를 사용합니다.
    • IRuntime 인터페이스를 사용하여 엔진 파일을 로딩하는 방법은 다음과 같습니다.
    #include <NvInferRuntimeCommon.h>
    
    // TensorRT 엔진 파일 로딩
    std::ifstream engine_file(engine_file_path, std::ios::binary);
    engine_file.seekg(0, std::ios::end);
    const size_t engine_size = engine_file.tellg();
    engine_file.seekg(0, std::ios::beg);
    std::vector<char> engine_data(engine_size);
    engine_file.read(engine_data.data(), engine_size);
    nvinfer1::IRuntime* runtime = nvinfer1::createInferRuntime(gLogger);
    nvinfer1::ICudaEngine* engine = runtime->deserializeCudaEngine(engine_data.data(), engine_size, nullptr);
    
  3. TensorRT 엔진 파일을 사용하여 추론하기

    • TensorRT 엔진 파일을 사용하여 추론하기 위해서는 IExecutionContext 인터페이스를 사용합니다.
    • IExecutionContext 인터페이스를 사용하여 추론하는 방법은 다음과 같습니다.
    #include <NvInferRuntimeCommon.h>
    
    // TensorRT 엔진 파일을 사용하여 추론
    nvinfer1::IExecutionContext* context = engine->createExecutionContext();
    context->execute(batch_size, bindings);
    

위의 코드에서 engine_file_path는 TensorRT 엔진 파일의 경로를, batch_size는 추론할 배치 크기를, bindings는 입력 및 출력 바인딩 정보를 나타내는 std::vector<void*>입니다.

TensorRT C++에서 엔진 파일을 로딩하여 추론하는 방법에 대해 설명드렸습니다. 참고하시길 바랍니다.


  • 답변이 어떠셨나요? 괜찮았다고 생각하신다면 아래 :heart:를 한 번 눌러주시길 부탁드려요!
1개의 좋아요
  • 아래 답변은 OpenAI의 GPT-4 모델로 자동 생성한 것으로, 정확하지 않을 수 있습니다.
  • 잘못된 답변을 보셨다면 댓글로 첨삭 지도 부탁드립니다. :sweat_smile:

안녕하세요!

TensorRT를 사용하여 ONNX 모델을 엔진 파일로 변환하고, C++에서 엔진 파일을 로드하여 추론하는 예제를 설명드리겠습니다.

먼저, TensorRT에서 ONNX 모델을 엔진 파일로 변환하는 과정은 다음과 같습니다.

  1. ONNX 모델을 TensorRT 빌더로 로드합니다.
  2. 최적화 옵션을 설정하고, 엔진을 빌드합니다.
  3. 빌드된 엔진을 파일로 저장합니다.

이제 C++에서 TensorRT 엔진 파일을 로드하고 추론하는 과정은 다음과 같습니다.

  1. TensorRT 런타임을 생성합니다.
  2. 저장된 엔진 파일을 불러옵니다.
  3. 런타임에서 엔진을 디-시리얼라이즈합니다.
  4. 엔진에서 실행 컨텍스트를 생성하고, 입력 및 출력 버퍼를 설정합니다.
  5. 추론을 실행하고 결과를 얻습니다.

예제 코드는 아래와 같습니다.

#include <iostream>
#include <fstream>
#include <NvInfer.h>
#include <NvOnnxParser.h>
#include <cuda_runtime_api.h>

using namespace nvinfer1;

int main() {
    // 1. TensorRT 런타임 생성
    IRuntime* runtime = createInferRuntime(gLogger);

    // 2. 저장된 엔진 파일 불러오기
    std::ifstream engineFile("your_engine_file.trt", std::ios::binary);
    if (!engineFile) {
        std::cerr << "Failed to open engine file." << std::endl;
        return 1;
    }

    engineFile.seekg(0, engineFile.end);
    size_t engineSize = engineFile.tellg();
    engineFile.seekg(0, engineFile.beg);

    std::vector<char> engineData(engineSize);
    engineFile.read(engineData.data(), engineSize);
    engineFile.close();

    // 3. 런타임에서 엔진 디-시리얼라이즈
    ICudaEngine* engine = runtime->deserializeCudaEngine(engineData.data(), engineSize, nullptr);

    // 4. 엔진에서 실행 컨텍스트 생성 및 입력/출력 버퍼 설정
    IExecutionContext* context = engine->createExecutionContext();
    int inputIndex = engine->getBindingIndex("input_tensor_name");
    int outputIndex = engine->getBindingIndex("output_tensor_name");

    float* inputBuffer;
    float* outputBuffer;
    cudaMalloc(&inputBuffer, batchSize * inputSize * sizeof(float));
    cudaMalloc(&outputBuffer, batchSize * outputSize * sizeof(float));

    // 5. 추론 실행 및 결과 얻기
    void* buffers[] = {inputBuffer, outputBuffer};
    cudaMemcpy(inputBuffer, inputData, batchSize * inputSize * sizeof(float), cudaMemcpyHostToDevice);
    context->execute(batchSize, buffers);
    cudaMemcpy(outputData, outputBuffer, batchSize * outputSize * sizeof(float), cudaMemcpyDeviceToHost);

    // 메모리 해제 및 종료
    cudaFree(inputBuffer);
    cudaFree(outputBuffer);
    context->destroy();
    engine->destroy();
    runtime->destroy();

    return 0;
}

위 예제에서 your_engine_file.trt는 TensorRT로 변환한 엔진 파일의 경로이며, input_tensor_nameoutput_tensor_name은 ONNX 모델의 입력 및 출력 텐서 이름입니다. 또한, inputDataoutputData는 입력 및 출력 데이터를 저장할 호스트 메모리 포인터입니다.

이 예제를 사용하여 TensorRT 엔진 파일을 로드하고 추론을 실행할 수 있습니다. 추가적인 정보가 필요하시면, 공식 TensorRT 문서를 참조하시기 바랍니다: TensorRT Developer Guide


  • 답변이 어떠셨나요? 괜찮았다고 생각하신다면 아래 :heart:를 한 번 눌러주시길 부탁드려요!
1개의 좋아요

결국 해결했습니다.
일단 아이디어는 sample ONNX MNIST 예제가 있어서
거기서 Onnx를 로딩하는 engine을 tensorRT engine file을 로딩하여 대체하는 것이었습니다.
그러면 기타 다른 기능은 예제 그대로 가져 갈 수 있었으니까요.

수정하면서 onnx 파일에서 network 구조를 뽑아서 input, output의 사이즈를 체크하는 부분이
Build 맨 밑에 있는데, 그 관련된 것이 infer 함수 내에도 있어서
dim을 불러오던것을 상수로 바꿔주고 (입력 28x28 출력 10)
엔진 파일을 로딩해주니 onnx 파일 없이도 잘 돌아가는군요!!

혹시 속도 면에서 ONNX 와 TensorRT의 차이가 있으셨나요?