在嵌入式设备上部署深度学习模型一直是计算机视觉领域的难点和热点。作为一名长期从事边缘计算开发的工程师,我最近成功在树莓派4B上实现了YOLOv8目标检测模型的C++部署,整个过程踩了不少坑,也积累了一些实用经验。本文将详细记录从模型准备到最终部署的全流程,特别适合那些需要在无GPU环境下实现高效推理的开发者参考。
树莓派4B作为一款价格亲民的开发板,其ARM Cortex-A72四核处理器虽然性能有限,但通过合理的优化手段,完全可以胜任轻量级目标检测任务。我选择NCNN作为推理框架,主要看中它在ARM平台上的优异表现和轻量级特性。实测下来,在树莓派4B上运行YOLOv8n模型能达到约8FPS的推理速度,对于很多实际应用场景已经足够。
YOLOv8系列提供了多个不同规模的模型,从nano版本(yolov8n)到xlarge版本(yolov8x)。考虑到树莓派4B的计算资源限制,我强烈建议使用yolov8n.pt这个最小的模型。它的参数量仅3.2M,在COCO数据集上仍能达到37.3mAP的精度,是性能和速度的完美平衡。
提示:如果应用场景对精度要求不高但对实时性要求极高,可以考虑使用YOLOv8n-seg分割模型,它的推理速度比检测模型更快。
获取官方模型非常简单:
bash复制git clone https://github.com/ultralytics/ultralytics
cd ultralytics
wget https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n.pt
NCNN无法直接运行PyTorch的.pt模型,需要先转换为NCNN支持的格式。官方提供了便捷的转换脚本:
python复制from ultralytics import YOLO
# 加载PyTorch模型
model = YOLO('yolov8n.pt')
# 导出为ONNX格式
model.export(format='onnx')
# 使用NCNN的onnx2ncnn工具转换
./onnx2ncnn yolov8n.onnx yolov8n.param yolov8n.bin
转换过程中有几个关键点需要注意:
model.export(format='onnx', dynamic=True)我使用的是Raspberry Pi OS (64-bit)系统,建议在开始前执行系统更新:
bash复制sudo apt update && sudo apt upgrade -y
为了获得最佳性能,建议进行以下系统级优化:
OpenCV是计算机视觉的基础库,在树莓派上推荐从源码编译安装:
bash复制sudo apt install -y build-essential cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
sudo apt install -y libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libdc1394-22-dev
git clone https://github.com/opencv/opencv.git
cd opencv && mkdir build && cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF ..
make -j4
sudo make install
实测发现,使用OpenCV4.5以上版本能获得更好的多线程性能。
NCNN的编译过程需要特别注意ARM NEON指令集的优化:
bash复制sudo apt install -y libvulkan-dev vulkan-utils
git clone https://github.com/Tencent/ncnn.git
cd ncnn && mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release -DNCNN_VULKAN=OFF -DNCNN_OPENMP=ON -DNCNN_THREADS=ON -DNCNN_RUNTIME_CPU=OFF -DNCNN_ARM82=ON ..
make -j4
sudo make install
关键编译选项说明:
NCNN_ARM82=ON:启用ARMv8.2指令集优化NCNN_OPENMP=ON:启用OpenMP多线程支持NCNN_VULKAN=OFF:树莓派4B不支持Vulkan,必须关闭整个项目采用标准的C++工程结构:
code复制yolov8-ncnn/
├── CMakeLists.txt
├── include/
│ └── yoloV8.h
├── src/
│ ├── yoloV8.cpp
│ └── main.cpp
└── models/
├── yolov8n.param
└── yolov8n.bin
CMake配置需要注意链接NCNN和OpenCV库:
cmake复制find_package(OpenCV REQUIRED)
find_package(ncnn REQUIRED)
add_executable(yolov8 src/main.cpp src/yoloV8.cpp)
target_link_libraries(yolov8 ncnn ${OpenCV_LIBS})
头文件yoloV8.h主要定义类接口:
cpp复制class YOLOv8 {
public:
YOLOv8(const std::string& param_path, const std::string& bin_path);
std::vector<Detection> detect(const cv::Mat& image);
private:
ncnn::Net net_;
float score_threshold_ = 0.5f;
float nms_threshold_ = 0.45f;
void preprocess(const cv::Mat& image, ncnn::Mat& input);
void postprocess(const ncnn::Mat& output, std::vector<Detection>& detections);
};
核心的预处理函数需要注意以下几点:
main.cpp实现完整的检测流程:
cpp复制int main() {
YOLOv8 detector("models/yolov8n.param", "models/yolov8n.bin");
cv::VideoCapture cap(0);
cv::Mat frame;
while (true) {
cap >> frame;
auto detections = detector.detect(frame);
for (const auto& det : detections) {
cv::rectangle(frame, det.bbox, cv::Scalar(0, 255, 0), 2);
cv::putText(frame, det.label, cv::Point(det.bbox.x, det.bbox.y-10),
cv::FONT_HERSHEY_SIMPLEX, 0.9, cv::Scalar(0, 255, 0), 2);
}
cv::imshow("YOLOv8 Detection", frame);
if (cv::waitKey(1) == 27) break;
}
return 0;
}
通过以下手段可以进一步提升推理速度:
bash复制./ncnn2int8 yolov8n.param yolov8n.bin yolov8n-int8.param yolov8n-int8.bin
cpp复制ncnn::set_cpu_powersave(0); // 最高性能模式
ncnn::set_omp_num_threads(4); // 使用全部4个核心
在不同配置下的性能对比:
| 配置 | 推理时间(ms) | FPS | 内存占用(MB) |
|---|---|---|---|
| FP32原始模型 | 125 | 8.0 | 280 |
| INT8量化模型 | 55 | 18.2 | 180 |
| 320x320输入 | 35 | 28.6 | 120 |
注意:量化后的模型精度会有约5%的mAP下降,需要根据应用场景权衡。
问题:转换后的模型在NCNN上运行报错
排查步骤:
问题:推理速度远低于预期值
优化建议:
perf工具分析热点函数问题:运行时报内存不足错误
解决方案:
在实际部署过程中,我发现树莓派4B的散热是个大问题。长时间运行会导致CPU降频,严重影响推理速度。建议加装散热风扇或散热片,保持芯片温度在60°C以下。另外,使用5V 3A的电源适配器能确保供电充足,避免因电流不足导致的性能下降。