Trên nền tảng Horizon Journey 6 (Nash), việc cấu hình input_type_rt là rgb và layout là NHWC mang lại lợi thế lớn về hiệu suất. Khi dữ liệu đầu vào từ cảm biến hoặc luồng xử lý trước đã ở định dạng này, cấu hình trên giúp loại bỏ các thao tác chuyển đổi định dạng dư thừa, từ đó giảm độ trễ (latency). Bài viết này sẽ hướng dẫn chi tiết cách thực hiện định lượng (quantization) cho mô hình YOLOv5s.
1. Chuẩn bị dữ liệu hiệu chuẩn (Calibration)
Dữ liệu hiệu chuẩn đóng vai trò quan trọng trong việc duy trì độ chính xác của mô hình sau khi chuyển đổi sang số nguyên (int8). Chúng ta sẽ sử dụng các tập lệnh hỗ trợ trong horizon_model_convert_sample để xử lý hình ảnh gốc.
Tập lệnh tiền xử lý 02_preprocess.sh được cấu hình như sau:
set -e -v
BASE_DIR=$(dirname $0)
cd $BASE_DIR
python3 ../../data_preprocess.py \
--src_dir ./images_source \
--dst_dir ./calib_data_rgb_f32 \
--pic_ext .rgb \
--read_mode opencv \
--saved_data_type float32
Trong tệp preprocess.py, chúng ta cần tùy chỉnh các bước biến đổi dữ liệu (Transformers) để khớp với yêu cầu của mô hình:
from horizon_tc_ui.data.transformer import (PadResizeTransformer,
BGR2RGBTransformer,
NormalizeTransformer)
def get_calib_transformers():
# Khởi tạo quy trình tiền xử lý dữ liệu
processing_pipeline = [
# Resize và bù lề để đạt kích thước 384x2048
PadResizeTransformer(target_size=(384, 2048)),
# Chuyển không gian màu từ BGR (OpenCV) sang RGB
BGR2RGBTransformer(data_format="HWC"),
# Chuẩn hóa giá trị pixel về dải [0, 1]
NormalizeTransformer(255.0)
]
return processing_pipeline
Các bước xử lý trên bao gồm:
- PadResizeTransformer: Đảm bảo kích thước ảnh đầu vào đồng nhất với đầu vào của mạng neural.
- BGR2RGBTransformer: Đổi thứ tự kênh màu, vì hầu hết các mô hình hiện đại được huấn luyện trên định dạng RGB thay vì BGR mặc định của OpenCV.
- NormalizeTransformer: Chia giá trị pixel cho 255 để đưa về định dạng số thực dấu phẩy động, hỗ trợ quá trình tính toán thống kê khi hiệu chuẩn.
2. Cấu hình tệp YAML cho trình biên dịch
Đây là tệp cấu hình cốt lõi để hb_compile thực hiện chuyển đổi mô hình sang định dạng chạy trên NPU của Journey 6.
calibration_parameters:
cal_data_dir: "./calib_data_rgb_f32"
quant_config: {
"model_config": {
"all_node_type": "int8",
"activation": {
"calibration_type": "max",
"max_percentile": 0.99999,
},
},
}
compiler_parameters:
compile_mode: latency
debug: true
jobs: 32
optimize_level: O2
input_parameters:
input_name: input
input_shape: 1x384x2048x3
input_layout_rt: NHWC
input_layout_train: NHWC
input_type_rt: rgb
input_type_train: rgb
std_value: 255.0
model_parameters:
march: nash-m
onnx_model: ./yolov5s_static.onnx
output_model_file_prefix: yolov5s_nash
working_dir: ./compile_output
3. Thực thi biên dịch mô hình
Sử dụng lệnh sau để bắt đầu quá trình định lượng và biên dịch:
hb_compile -c ./config_nash.yaml
Sau khi hoàn tất, hệ thống sẽ hiển thị bảng so sánh độ tương đồng Cosine (Cosine Similarity) để đánh giá chất lượng mô hình sau định lượng. Chỉ số càng gần 1.0 thì mô hình càng ít bị mất độ chính xác.
4. Kiểm chứng bằng Python Inference
Để đảm bảo mô hình hoạt động chính xác trước khi triển khai trên C++, chúng ta thực hiện chạy thử nghiệm với HBRuntime.
import cv2
import numpy as np
from horizon_tc_ui.hb_runtime import HBRuntime
def load_image_float(path):
img = cv2.imread(path).astype(np.float32)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = img / 255.0
return img[np.newaxis, :, :, :]
def load_image_int8(path):
img = cv2.imread(path).astype(np.uint8)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# Giả lập định dạng dữ liệu lượng tử hóa
img = (img - 128).astype(np.int8)
return img[np.newaxis, :, :, :]
def run_prediction(model_path, data_loader_func):
input_tensor = data_loader_func('./test_image.jpg')
engine = HBRuntime(model_path)
in_names = engine.input_names
out_names = engine.output_names
feeds = {in_names[0]: input_tensor}
results = engine.run(out_names, feeds)
print(f"--- Kết quả từ: {model_path} ---")
# In một phần dữ liệu đầu ra để kiểm tra nhanh
print(results[0][0][0][0][:5])
if __name__ == "__main__":
# Kiểm tra mô hình ONNX gốc
run_prediction("yolov5s_static.onnx", load_image_float)
# Kiểm tra mô hình đã định lượng (.bc)
run_prediction("./compile_output/yolov5s_nash_quantized_model.bc", load_image_int8)
Đoạn mã trên thực hiện các nhiệm vụ sau:
- Tiền xử lý: Tạo ra hai luồng dữ liệu, một dành cho mô hình float (0-1) và một dành cho mô hình int8 (thường được căn chỉnh tâm về 0).
- HBRuntime: Tải mô hình và thực thi trên phần cứng giả lập hoặc thực tế của Horizon.
- Xác thực: So sánh kết quả đầu ra giữa các phiên bản mô hình (Float, Calibrated, Quantized). Nếu các giá trị có xu hướng tương đồng và độ lệch nằm trong ngưỡng cho phép, mô hình đã sẵn sàng để triển khai thực tế.