编译
ncnn的编译安装官方仓库提供的教程还是蛮详细的,这里笔者参考Raspberry Pi编译的教程提供在radxa o6板子上的完整编译命令
git clone https://github.com/Tencent/ncnn.git
cd ncnn
git submodule update --init
sudo apt install build-essential git cmake libprotobuf-dev protobuf-compiler libomp-dev libopencv-dev
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DNCNN_VULKAN=ON -DNCNN_BUILD_EXAMPLES=ON ..
make -j$(nproc)
这里注意一下:NCNN_BUILD_BENCHMARK
默认是打开的,如果想要看到模型每个layer的耗时编译的时候可以设置:-DNCNN_BENCHMARK=ON
运行
运行benchmark主要关注网络结构本身的计算耗时,而不是具体的推理结果,所以只需要网络结构定义文件(即 ncnn 的 .param 文件)拷贝到编译好的benchmark文件夹内
cd build/benchmark
cp ../../benchmark/* ./
运行参数解读
参数 (Parameter) | 选项 (Options) | 默认值 (Default) | 说明 (Description) |
---|---|---|---|
loop count | 1 到 N 的整数 | 4 | 指定推理测试循环执行的次数,用于计算平均性能。 |
num threads | 1 到 N 的整数 | max_cpu_count | 指定用于推理的 CPU 线程数量。默认使用所有可用的 CPU 核心。 |
powersave | 0=所有核心, 1=仅小核, 2=仅大核 | 0 | 控制 CPU 核心的使用策略,用于功耗或性能测试(适用于大小核架构)。 |
gpu device | -1=仅CPU, 0=GPU0, 1=GPU1 ... | -1 | 指定使用的 GPU 设备进行推理。-1 表示仅使用 CPU。 |
cooling down | 0=禁用, 1=启用 | 1 | 是否在每次循环测试之间启用冷却等待,以避免过热影响性能测试结果。 |
param | ncnn 模型 .param 文件路径 | - (必须提供) | 指定要进行性能测试的 ncnn 网络结构定义文件(.param 文件)。 |
shape | 模型输入形状,格式为 width,height,channels 等 | - (必须提供) | 指定模型输入的形状(例如 224,224,3 )。 |
Benchmark
这里分别在CPU和GPU上运行Benchmark程序,并使用Gemini2.5 Pro大模型对结果数据进行解读
CPU测试
./benchncnn 4 8 0 -1 1
结论:
- 测试环境: 本次测试在 CPU 上进行,使用了 8 个线程,并启用了核心间冷却。
性能差异显著: 不同模型的推理速度差异很大。
- 最快梯队: 轻量级模型如
blazeface
(平均 1.95ms),shufflenet_v2
(平均 2.96ms),squeezenet_int8
(平均 3.15ms) 表现最佳。 - 最慢梯队: 复杂模型如
vision_transformer
(平均 232.46ms) 和vgg16
(平均约 42ms) 耗时最长。
- 最快梯队: 轻量级模型如
- INT8 量化效果: 对于支持 INT8 的模型,其量化版本(如
squeezenet_int8
,mobilenet_int8
,resnet50_int8
)通常比对应的浮点版本(FP32)运行更快,验证了量化在提升 CPU 推理速度上的有效性。 模型复杂度影响: 总体而言,模型越复杂(如 VGG, ResNet50, ViT),推理时间越长;模型越轻量(如 SqueezeNet, MobileNet, ShuffleNet),推理时间越短。
GPU测试
./benchncnn 4 8 0 0 1
参数解读- 测试环境: 本次测试主要在 GPU (Mali-G720-Immortalis) 上进行,同时指定了 8 个 CPU 线程,并启用了核心间冷却。
- INT8 优势: 对于大多数支持 INT8 的模型,其量化版本在 GPU 上的表现依然优于或接近 FP32 版本(例如
squeezenet_int8
,mobilenet_int8
,resnet18_int8
,resnet50_int8
,mobilenet_ssd_int8
)。但也存在例外,如vgg16_int8
反而比vgg16
慢。 模型性能差异: 不同模型在 GPU 上的性能差异仍然很大。
- 较快模型:
squeezenet_int8
(平均 3.16ms),mobilenet_int8
(平均 3.51ms),mobilenet
(平均 3.76ms) 等表现较好。 - 较慢模型:
vision_transformer
(平均 1081.32ms) 耗时极长,efficientnetv2_b0
(平均 124.66ms) 和一些目标检测模型(如mobilenetv2_yolov3
,yolov4-tiny
)也相对较慢。
- 较快模型:
波动性: 某些模型(如
mobilenet_v3
,mnasnet
,efficientnet_b0
)的最大耗时远高于平均耗时,可能表明 GPU 在运行这些模型时存在一定的性能波动或初始化开销。对比
模型 (Model) CPU 平均耗时 (ms) GPU 平均耗时 (ms) GPU 相对 CPU 加速比 squeezenet 5.62 16.57 ~0.34x (变慢) squeezenet_int8 3.15 3.16 ~1.00x (持平) mobilenet 5.25 3.76 ~1.40x mobilenet_int8 3.46 3.51 ~0.99x (持平) mobilenet_v2 4.11 4.85 ~0.85x (变慢) shufflenet_v2 2.96 15.22 ~0.19x (变慢) blazeface 1.95 6.17 ~0.32x (变慢) resnet18 6.79 7.39 ~0.92x (略慢) resnet18_int8 5.08 4.34 ~1.17x vgg16 42.23 32.07 ~1.32x vgg16_int8 42.11 44.89 ~0.94x (略慢) resnet50 14.11 16.55 ~0.85x (变慢) resnet50_int8 8.67 8.55 ~1.01x (持平) mobilenet_ssd 7.70 18.86 ~0.41x (变慢) mobilenet_ssd_int8 7.12 5.64 ~1.26x yolov4-tiny 16.10 60.69 ~0.27x (变慢) vision_transformer 232.46 1081.32 ~0.21x (变慢)
结论总结
GPU 并非普遍优于 CPU:
- 与预期不同,在此设备和 ncnn 框架下,Mali GPU 并未对所有模型提供加速。
- 相当一部分模型(包括 FP32 和部分 INT8)在 GPU 上的运行速度显著慢于在 8 核 CPU 上的速度。例如
vision_transformer
,yolov4-tiny
,shufflenet_v2
,squeezenet
(FP32) 等。
INT8 量化是关键,相对提升 GPU 表现:
- INT8 量化模型在 CPU 和 GPU 上通常都远快于其 FP32 版本。
- 对于 GPU 而言,INT8 模型的表现相对优于 FP32 版本。部分 INT8 模型(如
resnet18_int8
,mobilenet_ssd_int8
)在 GPU 上实现了对 CPU 的加速,而它们的 FP32 版本在 GPU 上反而更慢。 - 一些 INT8 模型在 CPU 和 GPU 上的性能非常接近(如
squeezenet_int8
,resnet50_int8
),显示 GPU 并未带来额外优势。
少数模型确实受益于 GPU:
- 存在少数模型,即使是 FP32 版本,在 GPU 上也获得了实际的性能提升,例如
mobilenet
和vgg16
。
- 存在少数模型,即使是 FP32 版本,在 GPU 上也获得了实际的性能提升,例如
最终建议:
- 不能默认 GPU 更快。在此平台上使用 ncnn 时,CPU(特别是结合 INT8 量化)在许多场景下是性能更优的选择。
- 必须通过实际基准测试(如
benchncnn
)来评估特定模型,以确定选用 CPU 还是 GPU 能获得最佳性能。