|
|
24.08.13 : 검증 데이터셋을 보는 중 검증 데이터 셋에는 의자 클래스와 책상 클래스를 가진 검증 데이터셋이 소수인것을 발견 유리문을 포함한 검증 데이터는 하나도 없음을 발견. 의자와 책상 데이터셋을 각각 20장씩 추가하여 진행하면 확률이 높아진다고 판단
그러나 의자와 책상 객체가 포함되어있는 데이터셋을 추가하고 난 이후에도 잘 인식되지 않음.
24.08.14 : 의자와 책상 등등의 물체들을 모두 장애물 영역으로 처리하여 하나로 취급하고 기존 9개의 클래스(배경포함)에서 floor, wall, ceiling, blockage, background 총 5개의 클래스로 데이터셋을 재구성하여 테스트 하기로 함.
기존 데이터셋을 다시 레이블링하여 V2증식으로 실행한 결과 바닥의 값이 NaN값이 나온것을 확인
확인결과 데이터 증식을 V2로 사용하면 바닥을 인식하지 못하는 것을 발견 V1으로 수정함
기존 9개의 클래스에서 5개로 줄인만큼 모델을 resnet101을 사용하지말고 resnet50으로 낮추고 V1기법을 사용하기로함
V2 데이터 증강을 사용하면 여전히 바닥 값이 nan값이 나와 취소. - 학습 중간에 계속해서 문제 파악이 필요.
이후부터는 V1으로 클래스를 직접 추가하여 데이터 증식을 수행하도록 함
2024.08.15~16: 기존 추론시간 약 0.3초를 0.1초로 줄이기 위해 tensorrt를 사용하기 위해 조사를 시작함
[TensorRT] Windows + TensorRT 설치하기 (tistory.com)
GitHub - NVIDIA-AI-IOT/torch2trt: An easy to use PyTorch to TensorRT converter
tensorrt 10.x 버전 부터는 nvidia에서 제공하는 torch2trt를 사용하면 쉽게 사용 가능한 것을 발견 python 에서는 작동 되는 것 같으나 opencv에서는 잘 모르겠음
1) cuda 버전에 맞는 tensorrt 설치 12.5 이므로 10.3 버전을 깔기로 결정함
https://developer.nvidia.com/tensorrt-getting-started
2) cuda 버전에 맞는 toolkit을 설치
CUDA Toolkit 12.5 Downloads | NVIDIA Developer
3)pytorch 모델을 onnx 로 export
pytorch 모델 저장과 ONNX 사용 - gaussian37
설치한 toolkit의 헤더파일과 tensorrt 헤더파일을 사용하기 위해 경로 설정
링커->입력-> 추가 종속성
nvinfer_10.lib
nvinfer_plugin_10.lib
nvonnxparser_10.lib
위에 3개를 입력 10.x 버전이후로는 _10이 붙는 것을 확인
tensorrt 엔진을 생성하기 위한 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | #include <NvInfer.h> #include <NvOnnxParser.h> #include <cuda_runtime_api.h> #include <iostream> #include <fstream> #include <chrono> #include <vector> #include <NvInferRuntimeCommon.h> using namespace nvinfer1; using namespace nvonnxparser; // Logger 클래스 정의 (TensorRT 로깅을 위해 사용) class Logger : public nvinfer1::ILogger { void log(Severity severity, const char* msg) noexcept override { // INFO 레벨이 아닌 로그만 출력 if (severity != Severity::kINFO) { std::cout << msg << std::endl; } } }; //엔진 파일생성(onnx->tensorrt변환) int main() { // TensorRT Logger 생성 Logger trtLogger; // TensorRT 빌더 생성 IBuilder* builder = createInferBuilder(trtLogger); if (!builder) { std::cerr << "TensorRT 빌더 생성 실패." << std::endl; return -1; } // 네트워크 정의 생성 INetworkDefinition* network = builder->createNetworkV2(0U); if (!network) { std::cerr << "TensorRT 네트워크 생성 실패." << std::endl; return -1; } // ONNX 파서를 사용해 모델 로드 IParser* parser = createParser(*network, trtLogger); if (!parser) { std::cerr << "TensorRT 파서 생성 실패." << std::endl; return -1; } // ONNX 모델을 파싱 if (!parser->parseFromFile("model101.onnx", static_cast<int>(ILogger::Severity::kWARNING))) { std::cerr << "ONNX 모델 파싱 실패." << std::endl; return -1; } // 빌더 설정 생성 IBuilderConfig* config = builder->createBuilderConfig(); if (!config) { std::cerr << "TensorRT 빌더 설정 생성 실패." << std::endl; return -1; } const char* inputTensorName = network->getInput(0)->getName(); // 첫 번째 입력 텐서의 이름 가져오기 // 최적화 프로필 설정 추가 auto profile = builder->createOptimizationProfile(); profile->setDimensions(inputTensorName, OptProfileSelector::kMIN, Dims4{ 1, 3, 256, 256 }); // 최소 크기 profile->setDimensions(inputTensorName, OptProfileSelector::kOPT, Dims4{ 1, 3, 256, 256 }); // 최적 크기 profile->setDimensions(inputTensorName, OptProfileSelector::kMAX, Dims4{ 1, 3, 256, 256 }); // 최대 크기 config->addOptimizationProfile(profile); // 워크스페이스 메모리 크기 설정 (1GB) config->setMemoryPoolLimit(MemoryPoolType::kWORKSPACE, 1 << 30); // 네트워크를 직렬화하여 엔진 생성 IHostMemory* serializedModel = builder->buildSerializedNetwork(*network, *config); if (!serializedModel) { std::cerr << "TensorRT 엔진 직렬화 실패." << std::endl; return -1; } // 엔진을 파일로 저장 std::ofstream engineFile("model.engine", std::ios::binary); if (!engineFile) { std::cerr << "엔진 파일 쓰기 실패." << std::endl; return -1; } engineFile.write(reinterpret_cast<const char*>(serializedModel->data()), serializedModel->size()); engineFile.close(); std::cout << "엔진 파일이 model.engine으로 저장되었습니다." << std::endl; // 엔진을 바로 사용하기 위해 역직렬화 (옵션) IRuntime* runtime = createInferRuntime(trtLogger); ICudaEngine* engine = runtime->deserializeCudaEngine(serializedModel->data(), serializedModel->size()); if (!engine) { std::cerr << "TensorRT 엔진 생성 실패." << std::endl; return -1; } return 0; } | cs |
엔진이 생성됨
엔진 파일 로딩하여 추론하기(수정중)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | #include <NvInfer.h> #include <NvOnnxParser.h> #include <cuda_runtime_api.h> #include <iostream> #include <fstream> #include <chrono> #include <vector> #include <NvInferRuntimeCommon.h> using namespace nvinfer1; using namespace nvonnxparser; // Logger 클래스 정의 (TensorRT 로깅을 위해 사용) class Logger : public nvinfer1::ILogger { void log(Severity severity, const char* msg) noexcept override { // INFO 레벨이 아닌 로그만 출력 if (severity != Severity::kINFO) { std::cout << msg << std::endl; } } }; int main() { Logger trtLogger; // 엔진 파일 로드 std::ifstream engineFile("model.engine", std::ios::binary); if (!engineFile) { std::cerr << "엔진 파일을 열 수 없습니다." << std::endl; return -1; } engineFile.seekg(0, std::ios::end); size_t engineSize = engineFile.tellg(); engineFile.seekg(0, std::ios::beg); std::vector<char> engineData(engineSize); engineFile.read(engineData.data(), engineSize); engineFile.close(); // 엔진 역직렬화 IRuntime* runtime = createInferRuntime(trtLogger); ICudaEngine* engine = runtime->deserializeCudaEngine(engineData.data(), engineSize, nullptr); if (!engine) { std::cerr << "TensorRT 엔진 로드 실패." << std::endl; return -1; } // 추론을 위한 실행 컨텍스트 생성 IExecutionContext* context = engine->createExecutionContext(); if (!context) { std::cerr << "실행 컨텍스트 생성 실패." << std::endl; return -1; } // 입력과 출력 텐서의 이름 정의 (예시) const char* inputName = "input_tensor_name"; const char* outputName = "output_tensor_name"; // 입력 및 출력 텐서의 차원 설정 int inputIndex = engine->getBindingIndex(inputName); int outputIndex = engine->getBindingIndex(outputName); Dims inputDims = engine->getBindingDimensions(inputIndex); Dims outputDims = engine->getBindingDimensions(outputIndex); const int batchSize = 1; const int inputSize = batchSize * inputDims.d[0] * inputDims.d[1] * inputDims.d[2]; const int outputSize = batchSize * outputDims.d[0] * outputDims.d[1] * outputDims.d[2]; std::vector<float> inputData(inputSize, 1.0f); // 모든 값을 1로 설정 (예시) std::vector<float> outputData(outputSize); // CUDA 메모리 할당 void* inputBuffer = nullptr; void* outputBuffer = nullptr; cudaMalloc(&inputBuffer, inputSize * sizeof(float)); cudaMalloc(&outputBuffer, outputSize * sizeof(float)); // TensorRT 컨텍스트에 텐서 주소 설정 context->setTensorAddress(inputName, inputBuffer); context->setTensorAddress(outputName, outputBuffer); // 만약 엔진이 동적 모양을 사용한다면, 입력 모양도 설정해야 합니다. // 여기서는 예시로 입력 차원 설정 (동적 모양 사용 시 필요) context->setInputShape(inputName, inputDims); // 입력 데이터를 GPU로 복사 cudaMemcpy(inputBuffer, inputData.data(), inputSize * sizeof(float), cudaMemcpyHostToDevice); // CUDA 스트림 생성 cudaStream_t stream; cudaStreamCreate(&stream); // 추론 시간 측정 시작 auto start = std::chrono::high_resolution_clock::now(); // 추론 실행 (enqueueV3 사용) context->enqueueV3(stream); // 추론 시간 측정 종료 cudaStreamSynchronize(stream); // 동기화 auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration<float, std::milli> duration = end - start; std::cout << "추론 시간: " << duration.count() << " ms" << std::endl; // 출력 데이터를 GPU에서 CPU로 복사 cudaMemcpy(outputData.data(), outputBuffer, outputSize * sizeof(float), cudaMemcpyDeviceToHost); // 결과 출력 (예시로 첫 번째 값을 출력) std::cout << "추론 결과 (첫 번째 출력 값): " << outputData[0] << std::endl; // CUDA 메모리 해제 cudaFree(inputBuffer); cudaFree(outputBuffer); // CUDA 스트림 파괴 cudaStreamDestroy(stream); return 0; } | cs |
확인 결과 10.x 버전에서 개선된 사항이 많아 로딩하는 방법이 달라진거 같음
https://discuss.pytorch.kr/t/tensorrt-c/1874
찾아보니 C++예제는 거의 없고 python이 대부분인 것을 확인
tensorrt sample 코드 nvidia 제공
TensorRT/samples at release/10.3 · NVIDIA/TensorRT · GitHub
tensorrt 공식 문서
Developer Guide :: NVIDIA Deep Learning TensorRT Documentation
tensorrt 버전 8.0 이상 부터 지원이 안되는 것들이 있는 것을 확인 찾아서 위의 추론 코드를 수정할 필요가 있음
