gpt4 book ai didi

cuda - 3 个不同大小向量的推力复变换

转载 作者:行者123 更新时间:2023-12-04 20:20:02 28 4
gpt4 key购买 nike

你好,我在 C+ 中有这个循环,我试图将它转换为推力,但没有得到相同的结果......
有任何想法吗?
谢谢你

C++ 代码

for (i=0;i<n;i++) 
for (j=0;j<n;j++)
values[i]=values[i]+(binv[i*n+j]*d[j]);

推力代码
thrust::fill(values.begin(), values.end(), 0);
thrust::transform(make_zip_iterator(make_tuple(
thrust::make_permutation_iterator(values.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexDivFunctor(n))),
binv.begin(),
thrust::make_permutation_iterator(d.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexModFunctor(n))))),
make_zip_iterator(make_tuple(
thrust::make_permutation_iterator(values.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexDivFunctor(n))) + n,
binv.end(),
thrust::make_permutation_iterator(d.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexModFunctor(n))) + n)),
thrust::make_permutation_iterator(values.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexDivFunctor(n))),
function1()
);

推力功能
struct IndexDivFunctor: thrust::unary_function<int, int>
{
int n;

IndexDivFunctor(int n_) : n(n_) {}

__host__ __device__
int operator()(int idx)
{
return idx / n;
}
};

struct IndexModFunctor: thrust::unary_function<int, int>
{
int n;

IndexModFunctor(int n_) : n(n_) {}

__host__ __device__
int operator()(int idx)
{
return idx % n;
}
};


struct function1
{
template <typename Tuple>
__host__ __device__
double operator()(Tuple v)
{
return thrust::get<0>(v) + thrust::get<1>(v) * thrust::get<2>(v);
}
};

最佳答案

首先,一些一般性评论。你的循环

for (i=0;i<n;i++) 
for (j=0;j<n;j++)
v[i]=v[i]+(B[i*n+j]*d[j]);

相当于标准 BLAS gemv手术

enter image description here

其中矩阵以行主要顺序存储。在设备上执行此操作的最佳方法是使用 CUBLAS,而不是由推力基元构建的东西。

话虽如此,您发布的推力代码绝对不可能做您的串行代码所做的事情。您看到的错误不是浮点关联性的结果。从根本上 thrust::transform将提供给输入迭代器的每个元素的仿函数应用,并将结果存储在输出迭代器上。要产生与您发布的循环相同的结果, thrust::transform call 需要对您发布的 fmad 仿函数执行 (n*n) 次操作。显然不是。此外,不能保证 thrust::transform将以一种避免内存竞争的方式执行求和/归约操作。

正确的解决方案可能是这样的:
  • 使用推力::变换来计算 的元素的 (n*n) 乘积乙 d
  • 使用推力::reduce_by_key 将乘积减少为部分和,产生 BD
  • 使用推力::变换将结果矩阵向量乘积添加到 v 以产生最终结果。

  • 在代码中,首先定义一个像这样的仿函数:
    struct functor
    {
    template <typename Tuple>
    __host__ __device__
    double operator()(Tuple v)
    {
    return thrust::get<0>(v) * thrust::get<1>(v);
    }
    };

    然后执行以下操作来计算矩阵向量乘法
      typedef thrust::device_vector<int> iVec;
    typedef thrust::device_vector<double> dVec;

    typedef thrust::counting_iterator<int> countIt;
    typedef thrust::transform_iterator<IndexDivFunctor, countIt> columnIt;
    typedef thrust::transform_iterator<IndexModFunctor, countIt> rowIt;

    // Assuming the following allocations on the device
    dVec B(n*n), v(n), d(n);

    // transformation iterators mapping to vector rows and columns
    columnIt cv_begin = thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexDivFunctor(n));
    columnIt cv_end = cv_begin + (n*n);

    rowIt rv_begin = thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexModFunctor(n));
    rowIt rv_end = rv_begin + (n*n);

    dVec temp(n*n);
    thrust::transform(make_zip_iterator(
    make_tuple(
    B.begin(),
    thrust::make_permutation_iterator(d.begin(),rv_begin) ) ),
    make_zip_iterator(
    make_tuple(
    B.end(),
    thrust::make_permutation_iterator(d.end(),rv_end) ) ),
    temp.begin(),
    functor());

    iVec outkey(n);
    dVec Bd(n);
    thrust::reduce_by_key(cv_begin, cv_end, temp.begin(), outkey.begin(), Bd.begin());
    thrust::transform(v.begin(), v.end(), Bd.begin(), v.begin(), thrust::plus<double>());

    当然,与使用专门设计的矩阵向量乘法代码(如 dgemv)相比,这是一种非常低效的计算方式。来自 CUBLAS。

    关于cuda - 3 个不同大小向量的推力复变换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7617160/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com