-
NCNN 对 AVX 的支持
NCNN 是一个高效的神经网络推理框架,主要针对移动端优化,但也支持桌面平台(x86 架构)。
在桌面平台上,NCNN 会利用 CPU 的 SIMD 指令集(包括 AVX 和 AVX2)进行加速。 -
如果 CPU 支持 AVX 或 AVX2,NCNN 会在编译时和运行时自动启用相关优化,从而提升计算性能。
在编译 NCNN 时,可以通过 CMake 指定使用 AVX 指令集:
cmake -DNCNN_AVX=ON ..
make -j$(nproc)
NCNN_AVX=ON: 启用 AVX 优化。 如果 CPU 支持 AVX2,编译时会自动利用 AVX2 指令集。 确保编译环境中启用了支持
AVX 的编译器标志(如 -mavx 或 -mavx2)。
- 运行时检查 AVX 支持
NCNN 框架会在运行时检查目标 CPU 是否支持 AVX 指令集。如果不支持,NCNN 会自动回退到 SSE 或更基本的实现。
你可以通过 汇编指令或内置函数检测 CPU 是否支持 AVX
:
#include <immintrin.h>
#include <iostream>
bool cpu_support_avx()
{
int cpu_info[4];
__cpuid(cpu_info, 1);
return (cpu_info[2] & (1 << 28)) != 0; // AVX 位是 CPUID 的 ECX 寄存器的第 28 位
}
bool cpu_support_avx2()
{
int cpu_info[4];
__cpuid(cpu_info, 7); // 使用 leaf 7
return (cpu_info[1] & (1 << 5)) != 0; // AVX2 位是 EBX 的第 5 位
}
int main()
{
if (cpu_support_avx())
std::cout << "AVX is supported." << std::endl;
else
std::cout << "AVX is not supported." << std::endl;
if (cpu_support_avx2())
std::cout << "AVX2 is supported." << std::endl;
else
std::cout << "AVX2 is not supported." << std::endl;
return 0;
}
经测试 直接使用pip install pnnx
安装的ncnn预编译包是支持AVX的,写一段简单的代码来检测是否支持 AVX:
import ncnn
def check_avx_support():
try:
# 强制运行某些需要 AVX 的操作
model = ncnn.Net()
return True
except Exception as e:
print("Error:", e)
return False
if check_avx_support():
print("The ncnn Python package supports AVX.")
else:
print("The ncnn Python package does not support AVX.")
-
AVX 与性能
提升点:
加速矩阵运算(如卷积和全连接层)。
提高浮点运算密集型任务的吞吐量。
注意事项:
AVX 指令集在使用时会增加功耗,尤其是 AVX-512,可能会引发频率降低(thermal throttling)。
在老旧的 CPU(如仅支持 SSE 指令集)上运行 AVX 优化的二进制文件可能会崩溃。 -
如何优化 AVX 性能
选择正确的编译选项:确保编译时启用了 -mavx 或 -mavx2。
合理利用多线程:结合 OpenMP 等多线程技术,最大化利用 AVX 的并行能力。
避免频繁指令切换:在性能敏感的代码段,尽量避免 AVX 和 SSE 指令混用。 -
在移动端的替代优化
如果目标平台是移动端,则 AVX 指令集不可用,NCNN 会更多依赖 NEON(ARM 的 SIMD 扩展)。因此,开发时需要根据目标平台选择适配的指令集优化方案。
总结
AVX 指令集可以显著提升 NCNN 的推理性能,尤其是在桌面平台上运行时。
确保在编译和运行时都正确检测和使用 AVX。
对于需要跨平台支持的应用,建议为不同架构(x86/ARM)提供单独的优化版本。
ncnn部署
#include "net.h"
#include "mat.h"
#include <opencv2/opencv.hpp>
#include <iostream>
int main()
{
// 1. 加载 NCNN 模型
ncnn::Net net;
if (net.load_param("model.param") != 0 || net.load_model("model.bin") != 0)
{
std::cerr << "Failed to load NCNN model." << std::endl;
return -1;
}
// 2. 读取并预处理图像
cv::Mat netInputImg = cv::imread("input.jpg"); // 替换为实际图片路径
ncnn::Mat in = ncnn::Mat::from_pixels_resize(
netInputImg.data, ncnn::Mat::PIXEL_BGR2RGB,
netInputImg.cols, netInputImg.rows,
_netWidth, _netHeight
);
// 归一化
const float mean_vals[3] = {0.f, 0.f, 0.f};
const float norm_vals[3] = {1 / 255.f, 1 / 255.f, 1 / 255.f};
in.substract_mean_normalize(mean_vals, norm_vals);
// 3. 设置输入
ncnn::Extractor ex = net.create_extractor();
ex.input("input_blob_name", in); // 替换为实际输入名称
// 后续推理和处理
ncnn::Mat out;
ex.extract("output_blob_name", out); // 替换为实际输出名称
std::cout << "Inference completed!" << std::endl;
return 0;
}