使用NEON指令集进行优化
以上是对卷积的优化。如果你一次只处理一个元素:需要 16 次 mul需要 16 次 add需要 16 次 loadCPU 负担重NEON 版本一次处理 4 个元素:4 次 load → 1 次 vld1q4 次 mul → 1 次 vmulq4 次 add → 1 次 vaddq🚀。
·
float32x4_t acc = vdupq_n_f32(0.0f); // accumulator
for (int j = 0; j < 16; j += 4) {
float32x4_t v_data = vld1q_f32(data + j); // 加载4个float
float32x4_t v_kern = vld1q_f32(kernel + j); // 加载4个float
float32x4_t v_mul = vmulq_f32(v_data, v_kern); // 对应元素相乘
acc = vaddq_f32(acc, v_mul); // 累加到acc里
}
// 最后合并acc寄存器中的4个元素
float result = vgetq_lane_f32(acc, 0)
+ vgetq_lane_f32(acc, 1)
+ vgetq_lane_f32(acc, 2)
+ vgetq_lane_f32(acc, 3);
以上是对卷积的优化。
因为卷积里的 weighted sum 本质就是:
sum += a[i] * b[i]
如果你一次只处理一个元素:
-
需要 16 次 mul
-
需要 16 次 add
-
需要 16 次 load
-
CPU 负担重
NEON 版本一次处理 4 个元素:
-
4 次 load → 1 次 vld1q
-
4 次 mul → 1 次 vmulq
-
4 次 add → 1 次 vaddq
🚀 单轮循环效能提升 4 倍(在理想情况下)
卷积的核心操作是:
sum = a0*w0 + a1*w1 + a2*w2 + ... + ak*wk
对于一个普通写法的代码:
float sum =
src[i] * w0
+ src[i+1] * w1
+ src[i+2] * w2;
对应的NEON版本的代码如下:
NEON 版本(一次处理4个样本)
卷积核:
float32x4_t vw0 = vdupq_n_f32(w0);
float32x4_t vw1 = vdupq_n_f32(w1);
float32x4_t vw2 = vdupq_n_f32(w2);
处理数据:
float32x4_t v0 = vld1q_f32(src + i);
float32x4_t v1 = vld1q_f32(src + i + 1);
float32x4_t v2 = vld1q_f32(src + i + 2);
加权求和:
float32x4_t vsum = vmulq_f32(v0, vw0);
vsum = vmlaq_f32(vsum, v1, vw1);
vsum = vmlaq_f32(vsum, v2, vw2);
写回:
vst1q_f32(dst + i, vsum);
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)