首页 > 解决方案 > 如何使用 Eigen 库计算 uint8_t 数组的点积?

问题描述

我想在 C/C++ 中计算两个 uint8 类型数组的点积,天真实现为:

uint64_t dotproduct_u8_naive(uint8_t* a, uint8_t* b, uint32_t len)
{
    uint64_t res = 0;
    for(uint32_t i=0; i<len; i++) {
        res += a[i] * b[i];
    }
    return res;
}

由于 Eigen 库被声明为使用 SIMD 以实现快速,我想传递两个原始 C 数组,然后分配给 Eigen 的类型,然后计算 dotproduct 结果。实现如下:

uint64_t dotproduct_u8_eigen(uint8_t* a, uint8_t* b, uint32_t len)
{
    Eigen::Map<Eigen::Matrix<uint8_t, 1, Eigen::Dynamic, Eigen::RowMajor>> va(a, len);
    Eigen::Map<Eigen::Matrix<uint8_t, 1, Eigen::Dynamic, Eigen::RowMajor>> vb(b, len);
    uint64_t res = va.dot(vb);
    return res;
}

数组ab的元素不是零,但是,dotproduct_u8_eigen总是返回零,这与来自 的预期结果不同dotproduct_u8_naive()。这对我来说似乎很奇怪,因为我已经以相同的方式实现了 float32 类型向量点积并得到了正确的结果:

float dotproduct_f32_eigen(float* a, float* b, uint32_t len) {
    Eigen::Map<Eigen::Matrix<float, 1, Eigen::Dynamic, Eigen::RowMajor>> va(a, len);
    Eigen::Map<Eigen::Matrix<float, 1, Eigen::Dynamic, Eigen::RowMajor>> vb(b, len);
    float res = va.dot(vb);
    return res;
}

我的问题是:dotproduct_u8_eigen()错了吗?如何修改dotproduct_u8_eigen()以获得正确的结果?


我可以通过将 u8 矩阵转换为 uint64 矩阵来获得正确的结果,如下所示,这比简单的实现要慢得多:

uint64_t dotproduct_u8_eigen(uint8_t* a, uint8_t* b, uint32_t len)
{
    Eigen::Map<Eigen::Matrix<uint8_t, 1, Eigen::Dynamic, Eigen::RowMajor>> va(a, len);
    Eigen::Map<Eigen::Matrix<uint8_t, 1, Eigen::Dynamic, Eigen::RowMajor>> vb(b, len);
    
    Eigen::Matrix<uint64_t, 1, Eigen::Dynamic, Eigen::RowMajor> fa = va.cast<uint64_t>();
    Eigen::Matrix<uint64_t, 1, Eigen::Dynamic, Eigen::RowMajor> fb = vb.cast<uint64_t>();

    return fa.dot(fb);
}

标签: c++eigendot-product

解决方案


推荐阅读