Image Classification
Overview
This tutorial introduces how to run inference with a PyTorch ResNet50 model using the RBLN SDK C/C++ Runtime API
.
The model is compiled using the RBLN SDK Python API
, and the resulting *.rbln
file is used for inference using the
RBLN SDK C/C++ Runtime API
.
This approach combines the ease of model preparation in Python with the performance benefits of C/C++ for inference.
The entire code used in this tutorial can be found in RBLN Model Zoo.
Setup & Installation
Before you begin, ensure that your system environment is properly configured and that all required packages are installed. This includes:
- System Requirements:
- Packages Requirements:
- Installation Command:
| pip install torch torchvision cmake
pip install --extra-index-url https://pypi.rbln.ai/simple/ rebel-compiler>=0.7.4
|
Note
RBLN SDK is distributed as a .whl
package. Please note that the RBLN compiler and runtime
require an RBLN Portal account.
Compilation with RBLN Python API
Prepare the model
import the ResNet50
model from TorchVision.
| 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()
|
Compile the model
Once the torch model (torch.nn.Module) is prepared, compile it using rebel.compile_from_torch()
.
Then, save the compiled model using compiled_model.save()
.
| # 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")
|
Complete compilation
The above compilation code snippets are included in the compile.py.
To compile the model and generate the *.rbln
file, execute the script as follows:
| $ python compile.py --model-name=resnet50
|
Inference with RBLN SDK C/C++ Runtime API
Prepare CMake Build Script
This tutorial uses OpenCV for image pre/post-processing and argparse for CLI parameter parsing.
The following CMake script describes external package dependencies and linking.
| # 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})
|
Preprocess the input image using OpenCV APIs. The following code snippet reads an image,
performs color conversion, resizes it while maintaining the aspect ratio, crops the center,
and normalizes the pixel values.
| 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);
|
Run inference (Synchronous Execution)
The following code snippet shows synchronous inference.
| 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));
|
Run inference (Asynchronous Execution)
The following code snippet shows asynchronous inference.
| 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
The output logits
is a float32 array of size (1,1000), where each element represents the score for a
corresponding category in ImageNet.
We derive the top-1 index and print the corresponding category.
| // 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;
|
Release resources
Release the runtime and model.
| // Release Runtime
rbln_destroy_runtime(rt);
// Release Model
rbln_destroy_model(mod);
|
How to build using CMake
The complete code for the above example is included in the RBLN Model Zoo C++ examples.
To compile the code and generate the executable binary, run the following commands:
| $ mkdir ${SAMPLE_PATH}/build
$ cd ${SAMPLE_PATH}/build
$ cmake ..
$ make
|
How to run Executable file
After completing all steps, you can find the executable in the build directory.
| # 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
|
The results will look like this:
| Predicted category: tabby
|
Summary and References
This tutorial demonstrated how to compile a PyTorch ResNet50 model using the RBLN SDK Python API
and
run inference using the RBLN SDK C/C++ Runtime API
. The resulting executable generates
a prediction that can be decoded into a human-readable category.
References: