thrust::transform 输出的错误值

Wrong values of thrust::transform output

我正在尝试使用容器将 float3 数组转换为特定结构的容器。代码如下:

#include <thrust/device_ptr.h>
#include <thrust/extrema.h>
#include <thrust/reduce.h>
#include <thrust/execution_policy.h>
#include <thrust/functional.h>

// Ouput structure for thrust::transform
struct cloud_point_index_idx {
  unsigned int idx;
  float3 cloud_point;

  cloud_point_index_idx(unsigned int idx_, float3 cloud_point_) :
    idx(idx_), cloud_point(cloud_point_) {}

  bool operator < (const cloud_point_index_idx &p) const {
    return (idx < p.idx);
  }
};
// Functor for thrust::transform
struct point2voxelcentroid {
  float3 leaf_size;
  int min_x, min_y, min_z;

  point2voxelcentroid(float3 leaf_size,int min_x, int min_y, int min_z) {
    this->leaf_size = leaf_size;
    this->min_x = min_x; this->min_y = min_y; this->min_z = min_z;
  }

  __host__ __device__
  cloud_point_index_idx operator()(const float3 point) const {
    int ijk0 = static_cast<int>(floor(point.x / leaf_size.x) -
      static_cast<float>(min_x));
    int ijk1 = static_cast<int>(floor(point.y / leaf_size.y) -
      static_cast<float>(min_y));
    int ijk2 = static_cast<int>(floor(point.z / leaf_size.z) -
      static_cast<float>(min_z));

    int voxel_idx = ijk0 + ijk1 + ijk2;
    return cloud_point_index_idx(static_cast<unsigned int>(voxel_idx), point);
  }
};

int main() { // Example
  int num_points = 5;
  float3 data[5] = {{1, 0, 2}, {2, 1, 3}, {1, 1, -5}, {-1, 3, -2}, {-5, -2, 0}}; // Set the data
  int min_b_[3] = {-5, -2, -5};
  float3 leaf_size = {0.5, 0.5, 0.5};
  thrust::device_vector<float3> d_ptr(data, data + num_points); // Wrap it into a device_vector
  thrust::device_vector<cloud_point_index_idx> voxel_idx_vector; // Output
  voxel_idx_vector.reserve(num_points);
  thrust::transform(
    thrust::device,
    d_ptr.begin(), d_ptr.end(),
    voxel_idx_vector.begin(),
    point2voxelcentroid(leaf_size, min_b_[0], min_b_[1], min_b_[2]));

  thrust::host_vector<cloud_point_index_idx> indices; // Host vector to verify
  indices.reserve(num_points);
  thrust::copy(voxel_idx_vector.begin(), voxel_idx_vector.end(), indices.begin()); // Copy device to host

  // Print out values
  std::cout << "\n---\nAfter assignment\n";
  for (int i = 0; i < num_points; i++) {
    std::cout << "Voxel idx: " << indices[i].idx << ". Point: [" << indices[i].cloud_point.x << ", "
       << indices[i].cloud_point.y << ", " << indices[i].cloud_point.z << std::endl;
  }
}

我检查了我的仿函数值,它们似乎正确地解析了数据,但是当我打印我的 host_vector 时,我得到了非常奇怪的值,与我的输出必须是什么无关。我怀疑我没有正确初始化我的输出 host/device 向量。我尝试了其他方法来初始化它们,但它们在编译时都给我错误。我不确定我做错了什么。

这里有几个问题,但最严重的是 reserve 的使用,它实际上并没有为推力容器分配内存。

您需要做的是定义一个默认构造函数并在实例化时显式分配一个大小。像这样:

struct cloud_point_index_idx {
  int idx;
  float3 cloud_point;

  cloud_point_index_idx()=default;

  __host__ __device__
  cloud_point_index_idx(unsigned int idx_, float3 cloud_point_) :
    idx(idx_), cloud_point(cloud_point_) {}

  __host__ __device__
  bool operator < (const cloud_point_index_idx &p) const {
    return (idx < p.idx);
  }
};

(requires -std=c++11) 将在设备和主机上定义默认构造函数,容器必须在每个 class 实例初始化期间调用该构造函数。

你的代码修改对我有用:

$ cat bodgey.cu

#include <thrust/device_vector.h>
#include <thrust/device_ptr.h>
#include <thrust/extrema.h>
#include <thrust/reduce.h>
#include <thrust/execution_policy.h>
#include <thrust/functional.h>

#include <iostream>

// Ouput structure for thrust::transform
struct cloud_point_index_idx {
  int idx;
  float3 cloud_point;

  cloud_point_index_idx()=default;

  __host__ __device__
  cloud_point_index_idx(unsigned int idx_, float3 cloud_point_) :
    idx(idx_), cloud_point(cloud_point_) {}

  __host__ __device__
  bool operator < (const cloud_point_index_idx &p) const {
    return (idx < p.idx);
  }
};
// Functor for thrust::transform
struct point2voxelcentroid {
  float3 leaf_size;
  int min_x, min_y, min_z;

  point2voxelcentroid(float3 leaf_size,int min_x, int min_y, int min_z) {
    this->leaf_size = leaf_size;
    this->min_x = min_x; this->min_y = min_y; this->min_z = min_z;
  }

  __host__ __device__
  cloud_point_index_idx operator()(const float3 point) const {
    int ijk0 = static_cast<int>(floor(point.x / leaf_size.x) -
      static_cast<float>(min_x));
    int ijk1 = static_cast<int>(floor(point.y / leaf_size.y) -
      static_cast<float>(min_y));
    int ijk2 = static_cast<int>(floor(point.z / leaf_size.z) -
      static_cast<float>(min_z));

    int voxel_idx = ijk0 + ijk1 + ijk2;
    return cloud_point_index_idx(voxel_idx, point);
  }
};

int main() { // Example
  int num_points = 5;
  float3 data[5] = {{1, 0, 2}, {2, 1, 3}, {1, 1, -5}, {-1, 3, -2}, {-5, -2, 0}}; // Set the data
  int min_b_[3] = {-5, -2, -5};
  float3 leaf_size = {0.5, 0.5, 0.5};
  thrust::device_vector<float3> d_ptr(data, data + num_points); // Wrap it into a device_vector
  thrust::device_vector<cloud_point_index_idx> voxel_idx_vector(num_points); // Output
  thrust::transform(
    thrust::device,
    d_ptr.begin(), d_ptr.end(),
    voxel_idx_vector.begin(),
    point2voxelcentroid(leaf_size, min_b_[0], min_b_[1], min_b_[2]));

  thrust::host_vector<cloud_point_index_idx> indices(num_points); // Host vector to verify
  thrust::copy(voxel_idx_vector.begin(), voxel_idx_vector.end(), indices.begin()); // Copy device to host

  // Print out values
  std::cout << "\n---\nAfter assignment\n";
  for (int i = 0; i < num_points; i++) {
    std::cout << "Voxel idx: " << indices[i].idx << ". Point: [" << indices[i].cloud_point.x << ", "
       << indices[i].cloud_point.y << ", " << indices[i].cloud_point.z << std::endl;
  }
}

$ nvcc -std=c++11 -arch=sm_52 -o bodgey bodgey.cu 

$ ./bodgey 

---
After assignment
Voxel idx: 18. Point: [1, 0, 2
Voxel idx: 24. Point: [2, 1, 3
Voxel idx: 6. Point: [1, 1, -5
Voxel idx: 12. Point: [-1, 3, -2
Voxel idx: -2. Point: [-5, -2, 0