Как запустить на устройстве тягу::count_if? ( Куда )

Я хотел бы реализовать RANSAC. Я генерирую 60к точек и 500 плоскостей, и я хотел бы посчитать для каждой плоскости, сколько точек находится рядом с ними. Затем выберите тот, у которого максимальное значение.

После того, как я сгенерировал векторы (d_vec) и плоскости (d_pl) и передал их в GPU, я использую thrust::transform, а внутри него thrust:count_if для подсчета количества близких точек.

К сожалению, я получаю эту ошибку:

1>D:\Projects\cuda\CudaTest\CudaTest>"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0\bin\nvcc.exe" -gencode=arch=compute_30,code=\"sm_30,compute_30\" --use-local-env --cl-version 2015 -ccbin "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\x86_amd64" -x cu  -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0\include" -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0\include"     --keep-dir x64\Release -maxrregcount=0  --machine 64 --compile -cudart static     -DWIN32 -DWIN64 -DNDEBUG -D_CONSOLE -D_MBCS -Xcompiler "/EHsc /W3 /nologo /O2 /FS /Zi  /MD " -o x64\Release\kernel.cu.obj "D:\Projects\cuda\CudaTest\CudaTest\kernel.cu"
1>C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0\include\thrust/detail/type_traits/pointer_traits.h(201): error : calling a __host__ function("thrust::detail::vector_base< ::Vec3,  ::thrust::device_malloc_allocator< ::Vec3> > ::begin") from a __device__ function("thrust::cuda_cub::__transform::unary_transform_f< ::thrust::detail::normal_iterator< ::thrust::device_ptr< ::Plane> > ,  ::thrust::detail::normal_iterator< ::thrust::device_ptr<int> > ,  ::thrust::cuda_cub::__transform::no_stencil_tag,  ::plane_functor,  ::thrust::cuda_cub::__transform::always_true_predicate> ::operator ()<long long> ") is not allowed
1>C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0\include\thrust/detail/type_traits/pointer_traits.h(201): error : identifier "thrust::detail::vector_base< ::Vec3,  ::thrust::device_malloc_allocator< ::Vec3> > ::begin" is undefined in device code
1>D:/Projects/cuda/CudaTest/CudaTest/kernel.cu(84): error : calling a __host__ function("thrust::detail::vector_base< ::Vec3,  ::thrust::device_malloc_allocator< ::Vec3> > ::end") from a __device__ function("thrust::cuda_cub::__transform::unary_transform_f< ::thrust::detail::normal_iterator< ::thrust::device_ptr< ::Plane> > ,  ::thrust::detail::normal_iterator< ::thrust::device_ptr<int> > ,  ::thrust::cuda_cub::__transform::no_stencil_tag,  ::plane_functor,  ::thrust::cuda_cub::__transform::always_true_predicate> ::operator ()<long long> ") is not allowed
1>D:/Projects/cuda/CudaTest/CudaTest/kernel.cu(84): error : identifier "thrust::detail::vector_base< ::Vec3,  ::thrust::device_malloc_allocator< ::Vec3> > ::end" is undefined in device code

Как можно вызвать тягу :: count_if из кода устройства? Что я не так? Это полный код:

#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/generate.h>
#include <thrust/sort.h>
#include <thrust/copy.h>
#include <thrust/execution_policy.h>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <time.h>
#include <thrust/count.h>
#include <thrust/extrema.h>

struct Vec3 {
    float x;
    float y;
    float z;


    friend std::ostream& operator<<(std::ostream& os, const Vec3& dt);
};

std::ostream& operator<<(std::ostream& os, const Vec3& dt)
{
    os << dt.x << ", " << dt.y << ", " << dt.z;
    return os;
}

struct Plane {

    float a;
    float b;
    float c;
    float d;

    // https://keisan.casio.com/exec/system/1223596129
    static Plane FromPoints(Vec3 A, Vec3 B, Vec3 C) {
        Plane ret;

        ret.a = (B.y - A.y)*(C.z - A.z) - (C.y - A.y)*(B.z - A.z);
        ret.b = (B.z - A.z)*(C.x - A.x) - (C.z - A.z)*(B.x - A.x);
        ret.c = (B.x - A.x)*(C.y - A.y) - (C.x - A.x)*(B.y - A.y);

        ret.d = -(ret.a*A.x + ret.b*A.y + ret.c*A.z);

        return ret;

    }

};

Vec3 generator() {
    return {
        float(rand()) / float(RAND_MAX) * 1000.f,
        float(rand()) / float(RAND_MAX) * 1000.f,
        float(rand()) / float(RAND_MAX) * 1000.f
    };
}

int index_generator() {
    return rand() % 69632;
}

struct plane_distance {

    const Plane pl;

    __device__ plane_distance(const Plane pl) : pl(pl) {}

    __device__ bool operator()(const Vec3& vv) const {
        return fabsf(pl.a*vv.x + pl.b*vv.y + pl.c*vv.z + pl.d) / sqrtf(pl.a*pl.a + pl.b*pl.b + pl.c*pl.c) > 0.128f;
    }

};

struct plane_functor
{
    thrust::device_vector<Vec3>& d_vec;

    plane_functor(thrust::device_vector<Vec3>& d_vec) : d_vec(d_vec) {}

    __device__ int operator()(const Plane& pl) const {

        return thrust::count_if(thrust::device, d_vec.begin(), d_vec.end(), plane_distance(pl));

    }
};

int main(void)
{


    // Generate random points for testing

    std::cout << "Generating..." << std::endl;

    // generate random vectors serially
    thrust::host_vector<Vec3> h_vec(65536);
    std::generate(h_vec.begin(), h_vec.end(), generator);

    // Generate random planes
    thrust::host_vector<Plane> h_pl(512);
    std::generate(h_pl.begin(), h_pl.end(), [&h_vec]() {

        return Plane::FromPoints(
            h_vec[index_generator()],
            h_vec[index_generator()],
            h_vec[index_generator()]
        );

    });

    std::cout << "Transfer" << std::endl;

    // transfer data to the device
    thrust::device_vector<Vec3> d_vec = h_vec;
    thrust::device_vector<Plane> d_pl = h_pl;
    thrust::device_vector<int> counts(512);

    std::cout << "Searching" << std::endl;

    thrust::transform(thrust::device, d_pl.begin(), d_pl.end(), counts.begin(), plane_functor(d_vec));

    auto result = thrust::max_element(thrust::device, counts.begin(), counts.end());

    std::cout << "Press any key to exit" << std::endl;
    std::cin.get();

    return 0;
}

person Iter Ator    schedule 06.05.2018    source источник
comment
Проблема вызвана попыткой использовать контейнеры device_vector в коде устройства. Это незаконно   -  person talonmies    schedule 06.05.2018
comment
Мне нужно получить доступ к этому контейнеру device_vector внутри функции устройства. Как мне переработать этот код?   -  person Iter Ator    schedule 06.05.2018
comment
Приведение к необработанным указателям. Вызов преобразования также прерывается по той же причине. Либо используйте политики выполнения, либо API на основе тегов. Не смешивайте их   -  person talonmies    schedule 06.05.2018
comment
Я заменил ссылку указателем, но все равно получаю эту ошибку. Я пытался избежать count_if с помощью цикла, но получение размера d_vec и доступ к нему также приводит к ошибке компиляции.   -  person Iter Ator    schedule 06.05.2018
comment
это может представлять интерес   -  person Robert Crovella    schedule 06.05.2018


Ответы (1)


Как указано в комментариях, доступ к device_vector в коде устройства незаконен. Они (несмотря на свое название) являются абстракцией на стороне хоста во всех версиях Thrust, доступных на момент написания. Вы получаете ошибку, потому что ваш функтор вызывает создание копии device_vector в коде устройства, что требует создания новых контейнеров, вызовет выделение памяти и не сможет скомпилироваться.

Вы должны заставить это работать, используя необработанные указатели устройств, например:

struct plane_functor
{
    Vec3* d_vec0;
    Vec3* d_vec1;

    __host__ __device__ plane_functor(Vec3* d_vec0, Vec3* d_vec1) : d_vec0(d_vec0), d_vec1(d_vec1) {}

    __device__ int operator()(const Plane& pl) const {

        return thrust::count_if(thrust::device, d_vec0, d_vec1, plane_distance(pl));

    }
};

// ....

Vec3* d_vec0 = thrust::raw_pointer_cast(d_vec.data());
Vec3* d_vec1 = d_vec0 + (d_vec.end() - d_vec.begin());
thrust::transform(d_pl.begin(), d_pl.end(), counts.begin(), plane_functor( d_vec0, d_vec1 ) );

Обратите внимание: пока это компилируется для меня, я не могу запустить ваш код, потому что лямбда инициализации на стороне хоста взрывается, когда я пытаюсь его запустить. Также обратите пристальное внимание на то, как вы смешиваете исполнение на основе тегов и политик. Вызов thrust::transform в том виде, в котором он написан, потерпит неудачу даже с допустимым функтором из-за комбинации итераторов device_vector и thrust::device.

person Community    schedule 07.05.2018