콘텐츠로 이동

이미지 분류

Overview

이 튜토리얼에서는 RBLN SDK C/C++ Runtime API를 사용하여 PyTorch ResNet50 모델로 추론을 실행하는 방법을 소개합니다. 모델은 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를 사용한 컴파일

모델 준비

TorchVision에서 ResNet50 모델을 불러옵니다.

1
2
3
4
5
6
7
from torchvision import models  
import rebel  
import torch  

model_name = "resnet50"  
weights = models.get_model_weights(model_name).DEFAULT  
model = getattr(models, model_name)(weights=weights).eval()  

모델 컴파일

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, 224, 224], "float32")])  

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

컴파일 실행

위 컴파일 코드 스니펫은 compile.py에 포함되어 있습니다.
모델을 컴파일하고 *.rbln 파일을 생성하려면 다음 명령을 실행하세요:

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

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

CMake 빌드 스크립트 준비

이 튜토리얼은 이미지 전/후처리를 위해 OpenCV를, CLI 파라미터 파싱을 위해 argparse를 사용합니다.
아래 CMake 스크립트는 외부 패키지 종속성과 링크 설정을 설명합니다.

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

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

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

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

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

입력 데이터 준비

OpenCV API를 사용하여 입력 이미지를 전처리합니다.
다음 코드 스니펫은 이미지를 읽고 색상 변환, 종횡비 유지 리사이즈, 중앙 크롭, 픽셀 값 정규화를 수행합니다.

std::string input_path = "${SAMPLE_PATH}/tabby.jpg";  

// Read image  
cv::Mat input_image;  
try {  
    input_image = cv::imread(input_path);  
} catch (const cv::Exception &err) {  
    std::cerr << err.what() << std::endl;  
    std::exit(1);  
}  

// Convert BGR to RGB  
cv::Mat image;  
cv::cvtColor(input_image, image, cv::COLOR_BGR2RGB);  

// Resize while maintaining aspect ratio  
float scale = image.rows < image.cols ? 256. / image.rows : 256. / image.cols;  
cv::resize(image, image, cv::Size(), scale, scale, cv::INTER_LINEAR);  

// Center crop to 224x224  
image = image(cv::Rect((image.cols - 224) / 2, (image.rows - 224) / 2, 224, 224));  

// Normalize the image  
image.convertTo(image, CV_32F);  
cv::Vec3f mean(123.68, 116.28, 103.53);  
cv::Vec3f std(58.395, 57.120, 57.385);  
for (unsigned i = 0; i < image.rows; i++) {  
    for (unsigned j = 0; j < image.cols; j++) {  
        cv::subtract(image.at<cv::Vec3f>(i, j), mean, image.at<cv::Vec3f>(i, j));  
        cv::divide(image.at<cv::Vec3f>(i, j), std, image.at<cv::Vec3f>(i, j));  
    }  
}  

// Convert image to blob  
cv::Mat blob = cv::dnn::blobFromImage(image);  

동기식 추론 실행

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

std::string model_path = "${SAMPLE_PATH}/resnet50.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  
float *logits = static_cast<float *>(rbln_get_output(rt, 0));  

비동기식 추론 실행

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

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

// Allocate 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 for inference completion  
rbln_async_wait(rt, rid, 1000);  

후처리(Post Processing)

출력 logits는 ImageNet의 각 카테고리 점수를 나타내는 크기 (1,1000)의 float32 배열입니다.
top-1 인덱스를 구하고 해당 카테고리를 출력합니다.

// Postprocessing  
size_t max_idx = 0;  
float max_val = std::numeric_limits<float>::min();  
for (size_t i = 0; i < 1000; i++) {  
    if (logits[i] > max_val) {  
        max_val = logits[i];  
        max_idx = i;  
    }  
}  

// Print the predicted category  
std::cout << "Predicted category: " << IMAGENET_CATEGORIES[max_idx] << std::endl;  

리소스 해제

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

1
2
3
4
5
// Release Runtime  
rbln_destroy_runtime(rt);  

// Release Model  
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/image_classification -i ${SAMPLE_PATH}/tabby.jpg  -m ${SAMPLE_PATH}/resnet50.rbln  

# Asynchronous execution  
$ ${SAMPLE_PATH}/build/image_classification_async -i ${SAMPLE_PATH}/tabby.jpg  -m ${SAMPLE_PATH}/resnet50.rbln  

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

Predicted category: tabby  

Summary and References

이 튜토리얼에서는 RBLN SDK Python API를 사용하여 PyTorch ResNet50 모델을 컴파일하고
RBLN SDK C/C++ Runtime API로 추론을 실행하는 방법을 보여주었습니다.
생성된 실행 파일은 사람이 읽을 수 있는 카테고리 예측 결과를 제공합니다.

References: