Thrust::transform自定义函数

4

我想在CUDA中做一个非常基础的示例。我想对一组浮点数进行简单的计算。

vh[x] * k1 + k2

目前我正在尝试这样做,但它没有起作用:

代码 1

#include <vector>
#include <iostream>
#include <thrust/transform.h>
#include <thrust/functional.h>
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>

using namespace std;
using namespace thrust;

float k1 = 42, k2 = 7;

int main(void)
{
    vector<float> vh = { 0, 1, 2, 3, 4, 5, 6, 7 };
    device_vector<float> v = vh;
    device_vector<float> v_out(v.size());

    thrust::transform(v.begin(), v.end(), v_out.begin(), [=] __device__(float x) {
        return x*k1 + k2;
    });

    for (size_t i = 0; i < v_out.size(); i++)
        std::cout << v_out[i] << std::endl;
}

我在上面的代码中遇到了非常烦人的lambda函数错误,因此我尝试使用自定义函数,代码如下所示: 代码2
#include <vector>
#include <iostream>
#include <thrust/transform.h>
#include <thrust/functional.h>
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>

using namespace std;
using namespace thrust;

float k1 = 42, k2 = 7;

float multiply(float x)
{
    return x * k1 + k2;
}

int main(void) {
    vector<float> vh = { 0, 1, 2, 3, 4, 5, 6, 7 };
    device_vector<float> v = vh;
    device_vector<float> v_out(v.size());
    thrust::negate<float> op;

    thrust::transform(v.begin(), v.end(), v_out.begin(), multiply __device__(float x) );

    for (size_t i = 0; i < v_out.size(); i++)
        std::cout << v_out[i] << std::endl;

    std::getwchar();
}

有人能告诉我为什么 Code 1 和/或 Code 2 没有起作用吗?

你使用的是哪个CUDA和thrust版本? - talonmies
CUDA 7.5,我猜是Thrust 1.7.0。自从安装了CUDA以来,我还没有更新过它。 - Anonymous
1个回答

6
对于 Code 2,您必须将函数包装在对象中以创建一个函数对象。
对于 Code 1,您需要使用 --expt-extended-lambda nvcc 选项来启用完整的 lambda 支持。
您还必须将 k1k2 声明为 const,或者不使用静态变量(比如在 main 中声明)。
在生产代码中使用函数对象,除非您的 lambda 非常简单。
请参考以下示例代码以查看工作示例:
#include <vector>
#include <iostream>
#include <thrust/transform.h>
#include <thrust/functional.h>
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>

using namespace std;
using namespace thrust;



template<class T>
struct saxpi{
    T k1;
    T k2;
    saxpi(T _k1, T _k2){
        k1=_k1;
        k2=_k2;
    }
    __host__ __device__ T operator()(T &x) const{
        return x*k1+k2;
    }
};


int main(void)
{
    float kk1=1, kk2=5;
    vector<float> vh = { 0, 1, 2, 3, 4, 5, 6, 7 };
    device_vector<float> v = vh;
    device_vector<float> v_out(v.size());
    cout<<"Lambda:"<<endl;
    auto ff = [=]  __device__ (float x) {return kk1*x +kk2;};

    thrust::transform(v.begin(),v.end(),v_out.begin(),ff);

    for (size_t i = 0; i < v_out.size(); i++)
        std::cout << v_out[i] << std::endl;

    cout<<"Functor:"<<endl;
    saxpi<float> f(kk1,kk2);
    v_out.clear();
    v_out.resize(v.size());
    thrust::transform(v.begin(),v.end(),v_out.begin(),f);


    for (size_t i = 0; i < v_out.size(); i++)
            std::cout << v_out[i] << std::endl;

}

使用以下选项编译它:--expt-extended-lambda -std=c++11
Lambda:
5
6
7
8
9
10
11
12
Functor:
5
6
7
8
9
10
11
12

非常感谢!你能解释一下 host device 和仅有的 device 之间的区别吗? - Anonymous
1
host device 只是一种简写方式,可以让我们编写一次函数,并告诉编译器生成两个版本的相同代码:一个是针对 CPU 的 x86 汇编,另一个是针对 GPU 的 PTX。 - Davide Spataro
这个测试例子对我来说即使没有__host__限定符也能工作。 - HEKTO

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接