콘텐츠로 이동

객체 감지

Overview

이 튜토리얼에서는 RBLN SDK C/C++ Runtime API를 사용하여 PyTorch YOLOv8 모델로 추론을 실행하는 방법을 배웁니다. 모델은 RBLN SDK Python API를 사용해 컴파일하며, 생성된 *.rbln 파일은 RBLN SDK C/C++ Runtime API로 추론에 사용됩니다.
이 접근 방식은 Python에서 모델 준비의 편의성과 C/C++의 성능 이점을 결합합니다. 튜토리얼에 사용된 전체 코드는 RBLN Model Zoo에서 확인할 수 있습니다.

Setup & Installation

시작하기 전에 시스템 환경이 올바르게 구성되어 있으며, 필요한 모든 필수 패키지가 설치되어 있는지 확인하십시오. 다음 항목이 포함됩니다:

Note

RBLN SDK는 .whl 패키지로 배포됩니다. RBLN 컴파일러와 런타임을 사용하려면 RBLN Portal 계정이 필요합니다.

RBLN Python API를 사용한 컴파일

모델 준비

ultralytics 라이브러리에서 YOLOv8m 모델을 임포트하고 포워드 패스를 실행하여 모델을 초기화합니다.

1
2
3
4
5
6
7
8
from ultralytics import YOLO  
import rebel  
import torch  

model_name = "yolov8m"  
yolo = YOLO(f"{model_name}.pt")  
model = yolo.model.eval()  
model(torch.zeros(1, 3, 640, 640))  

모델 컴파일

Torch 모델(torch.nn.Module)이 준비되면 rebel.compile_from_torch()로 컴파일합니다. compiled_model.save()로 컴파일된 모델을 저장합니다.

1
2
3
4
5
# Compile the model  
compiled_model = rebel.compile_from_torch(model, [ ("x", [1, 3, 640, 640], "float32") ])  

# Save the compiled model to local storage  
compiled_model.save(f"{model_name}.rbln")  

컴파일 실행

컴파일 코드는 compile.py에 포함되어 있습니다. 다음 명령으로 스크립트를 실행하여 .rbln 파일을 생성하세요:

$ python compile.py --model-name=yolov8m  

RBLN SDK C/C++ Runtime API를 사용한 추론

CMake 빌드 스크립트 준비

예제 애플리케이션은 OpenCV로 이미지 전/후처리를 수행하고, argparse로 CLI 파라미터를 파싱합니다.
아래 CMake 스크립트는 외부 패키지 종속성과 링크 설정을 설명합니다.

# Define dependencies for external Package  
include(FetchContent)  
include(cmake/opencv.cmake)  
include(cmake/argparse.cmake)  

# Define the name of executable  
add_executable(object_detection main.cc)  

# Update link info for package dependencies: OpenCV  
find_package(OpenCV CONFIG REQUIRED)  
target_link_libraries(object_detection ${OpenCV_LIBS})  

# Update link info for dependencies: RBLN  
find_package(rbln CONFIG REQUIRED)  
target_link_libraries(object_detection rbln::rbln_runtime)  

# Update including dependencies: argparse  
target_include_directories(object_detection PRIVATE ${argparse_INCLUDE_DIRS})  

입력 데이터 준비

OpenCV API를 사용하여 입력 이미지를 전처리합니다. 아래 코드에서는 이미지를 읽고 전처리하는 과정을 보여줍니다.

1
2
3
4
5
6
7
8
9
std::string input_path = "${SAMPLE_PATH}/people4.jpg";  
cv::Mat image;  
try {  
    image = cv::imread(input_path);  
} catch (const cv::Exception &err) {  
    std::cerr << err.what() << std::endl;  
    std::exit(1);  
}  
cv::Mat blob = cv::dnn::blobFromImage(GetSquareImage(image, 640), 1./255., cv::Size(), cv::Scalar(), true, false, CV_32F);  

동기식 추론 실행

아래 코드는 동기식 추론 예시를 보여줍니다.

std::string model_path = "${SAMPLE_PATH}/yolov8m.rbln";  
RBLNModel *mod = rbln_create_model(model_path.c_str());  
RBLNRuntime *rt = rbln_create_runtime(mod, "default", 0, 0);  

// Set input data  
rbln_set_input(rt, 0, blob.data);  

// Run sync inference  
rbln_run(rt);  

// Get output results  
void *data = rbln_get_output(rt, 0);  

비동기식 추론 실행

아래 코드는 비동기식 추론 예시를 보여줍니다.

std::string model_path = "${SAMPLE_PATH}/yolov8m.rbln";  
RBLNModel *mod = rbln_create_model(model_path.c_str());  
RBLNRuntime *rt = rbln_create_async_runtime(mod, "default", 0, 0);  

// Alloc output buffer  
auto buf_size = rbln_get_layout_nbytes(rbln_get_output_layout(rt, 0));  
std::vector<float> logits(buf_size/sizeof(float));  

// Run async inference  
int rid = rbln_async_run(rt, blob.data, logits.data());  

// Wait inference done  
rbln_async_wait(rt, rid, 1000);  

후처리(Post Processing)

출력 데이터(float32 배열, shape=(1,84,8400))에 대해 NMS를 수행하고 바운딩 박스를 그립니다.
아래 코드는 처리 과정을 개략적으로 보여줍니다:

// Postprocessing for NMS  
const RBLNTensorLayout *layout = rbln_get_output_layout(rt, 0);  
cv::Mat logits{layout->ndim, layout->shape, CV_32F};  
memcpy(logits.data, data, rbln_get_layout_nbytes(layout));  

std::vector<cv::Rect> nms_boxes;  
std::vector<float> nms_confidences;  
std::vector<size_t> nms_class_ids;  
for (size_t i = 0; i < layout->shape[2]; i++) {  
    auto cx = logits.at<float>(0, 0, i);  
    auto cy = logits.at<float>(0, 1, i);  
    auto w = logits.at<float>(0, 2, i);  
    auto h = logits.at<float>(0, 3, i);  
    auto x = cx - w / 2;  
    auto y = cy - h / 2;  
    cv::Rect rect{static_cast<int>(x), static_cast<int>(y), static_cast<int>(w), static_cast<int>(h)};  
    float confidence = std::numeric_limits<float>::min();  
    int cls_id;  
    for (size_t j = 4; j < layout->shape[1]; j++) {  
        if (confidence < logits.at<float>(0, j, i)) {  
            confidence = logits.at<float>(0, j, i);  
            cls_id = j - 4;  
        }  
    }  
    nms_boxes.push_back(rect);  
    nms_confidences.push_back(confidence);  
    nms_class_ids.push_back(cls_id);  
}  
std::vector<int> nms_indices;  
cv::dnn::NMSBoxes(nms_boxes, nms_confidences, 0.25f, 0.45f, nms_indices);  
cv::Mat output_img = image.clone();  
for (size_t i = 0; i < nms_indices.size(); i++) {  
    auto idx = nms_indices[i];  
    auto class_id = nms_class_ids[idx];  
    auto scaled_box = ScaleBox(nms_boxes[idx], output_img.size(), 640);  
    cv::rectangle(output_img, scaled_box, cv::Scalar(255, 0, 0));  
    std::stringstream ss;  
    ss << COCO_CATEGORIES[class_id] << ": " << nms_confidences[idx];  
    cv::putText(output_img, ss.str(), scaled_box.tl() - cv::Point(0, 1), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(255, 0, 0));  
}  
cv::imwrite("result.jpg", output_img);  

리소스 해제

런타임과 모델을 해제합니다.

rbln_destroy_runtime(rt);  
rbln_destroy_model(mod);  

CMake 빌드 방법

예제 코드는 RBLN Model Zoo C++ 예제에 포함되어 있습니다.
아래 명령으로 컴파일하고 실행 파일을 생성하세요:

1
2
3
4
$ mkdir ${SAMPLE_PATH}/build  
$ cd ${SAMPLE_PATH}/build  
$ cmake ..  
$ make  

실행 파일 사용 방법

모든 단계가 완료된 후, 빌드 디렉토리에서 실행 파일을 확인할 수 있습니다.

1
2
3
4
5
# Synchronous execution  
$ ${SAMPLE_PATH}/build/object_detection -i ${SAMPLE_PATH}/people4.jpg  -m ${SAMPLE_PATH}/yolov8m.rbln  

# Asynchronous execution  
$ ${SAMPLE_PATH}/build/object_detection_async -i ${SAMPLE_PATH}/people4.jpg  -m ${SAMPLE_PATH}/yolov8m.rbln  

결과는 다음과 같이 표시됩니다: Image

Summary and References

이 튜토리얼에서는 RBLN SDK Python API를 사용하여 PyTorch YOLOv8 모델을 컴파일하고,
RBLN SDK C/C++ Runtime API로 추론을 실행하는 방법을 보여주었습니다.

References: