You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM Neon intrinsics转x86/x64 Windows代码正确性咨询

代码转换正确性分析:ARM Neon均值缩放函数转Windows x86/x64

原ARM Neon函数的核心逻辑

原函数针对通道交错的输入数据(如RGBRGBRGB...,每个像素占连续3个float),将其转换为通道分离的输出格式(先存储所有像素的通道0,再通道1,最后通道2),同时完成均值减法和缩放操作:

void NeonMeanScale(const float *din, float *dout, int size,
                   const std::vector<float> mean,
                   const std::vector<float> scale) {
  if (mean.size() != 3 || scale.size() != 3) {
    std::cerr << "[ERROR] mean or scale size must equal to 3" << std::endl;
    exit(1);
  }
  float32x4_t vmean0 = vdupq_n_f32(mean[0]);
  float32x4_t vmean1 = vdupq_n_f32(mean[1]);
  float32x4_t vmean2 = vdupq_n_f32(mean[2]);
  float32x4_t vscale0 = vdupq_n_f32(scale[0]);
  float32x4_t vscale1 = vdupq_n_f32(scale[1]);
  float32x4_t vscale2 = vdupq_n_f32(scale[2]);

  float *dout_c0 = dout;
  float *dout_c1 = dout + size;
  float *dout_c2 = dout + size * 2;

  int i = 0;
  for (; i < size - 3; i += 4) {
    float32x4x3_t vin3 = vld3q_f32(din);
    float32x4_t vsub0 = vsubq_f32(vin3.val[0], vmean0);
    float32x4_t vsub1 = vsubq_f32(vin3.val[1], vmean1);
    float32x4_t vsub2 = vsubq_f32(vin3.val[2], vmean2);
    float32x4_t vs0 = vmulq_f32(vsub0, vscale0);
    float32x4_t vs1 = vmulq_f32(vsub1, vscale1);
    float32x4_t vs2 = vmulq_f32(vsub2, vscale2);
    vst1q_f32(dout_c0, vs0);
    vst1q_f32(dout_c1, vs1);
    vst1q_f32(dout_c2, vs2);

    din += 12;
    dout_c0 += 4;
    dout_c1 += 4;
    dout_c2 += 4;
  }
  for (; i < size; i++) {
    *(dout_c0++) = (*(din++) - mean[0]) * scale[0];
    *(dout_c1++) = (*(din++) - mean[1]) * scale[1];
    *(dout_c2++) = (*(din++) - mean[2]) * scale[2];
  }
}

转换后的Windows代码的错误

转换后的代码错误地假设输入din是通道分离格式(先所有通道0像素,再通道1,再通道2),但实际输入来自OpenCV的cv::Mat,是通道交错格式(和原ARM代码的输入布局一致),这导致数据读取逻辑完全错误,计算结果混乱:

void NeonMeanScale(const float *din, float *dout, int size,
                   const std::vector<float> mean,
                   const std::vector<float> scale) {
  if (mean.size() != 3 || scale.size() != 3) {
    std::cerr << "[ERROR] mean or scale size must equal to 3" << std::endl;
    exit(1);
  }

  for (int i = 0; i < size; ++i) {
    dout[i] = (din[i] - mean[0]) * scale[0];
    dout[size + i] = (din[size + i] - mean[1]) * scale[1];
    dout[size * 2 + i] = (din[size * 2 + i] - mean[2]) * scale[2];
  }
}

修正后的Windows代码

修正后的代码严格对齐原ARM函数的逻辑,处理通道交错的输入,输出通道分离的结果:

void MeanScale(const float *din, float *dout, int size,
               const std::vector<float> mean,
               const std::vector<float> scale) {
  if (mean.size() != 3 || scale.size() != 3) {
    std::cerr << "[ERROR] mean or scale size must equal to 3" << std::endl;
    exit(1);
  }

  float *dout_c0 = dout;
  float *dout_c1 = dout + size;
  float *dout_c2 = dout + size * 2;

  for (int i = 0; i < size; ++i) {
    // 读取当前像素的3个通道(交错格式),计算后写入对应通道的输出区域
    *(dout_c0++) = (*din++ - mean[0]) * scale[0];
    *(dout_c1++) = (*din++ - mean[1]) * scale[1];
    *(dout_c2++) = (*din++ - mean[2]) * scale[2];
  }
}

修正说明

  • 输入din按交错格式读取:每个像素占连续3个float,依次为通道0、通道1、通道2;
  • 输出保持通道分离格式:dout_c0存储所有像素的通道0结果,dout_c1存储通道1,dout_c2存储通道2;
  • 逻辑完全匹配原ARM代码的逐像素处理分支,去掉Neon批量指令后,功能和原代码一致。

内容的提问来源于stack exchange,提问作者Prashant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 00:04:51