Tối ưu hóa định lượng YOLOv5s với cấu hình RGB-NHWC trên nền tảng Horizon Journey 6

Trên nền tảng Horizon Journey 6 (Nash), việc cấu hình input_type_rtrgblayoutNHWC 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ế.

Thẻ: Horizon-Robotics YOLOv5 Model-Quantization deep-learning NPU

Đăng vào ngày 2 tháng 9 lúc 06:21