Thrustを使った点群処理
2022/4/15
@第23回ロボティクス勉強会
neka-nat
自己紹介
独立系ロボットエンジニア
neka-nat
https://twitter.com/neka_nat
前回のロボゼミでの発表
今回の内容
今回の内容
今回の内容
(私がやってる)GPU計算できるようにするまでの流れ
Thrustとは?
https://developer.nvidia.com/thrust
並列計算で重要な演算①〜transformとreduce〜
// transformのサンプル
int data[10] = {-5, 0, 2, -3, 2, 4, 0, -1, 2, 8};
thrust::negate<int> op;
thrust::transform(thrust::host, data, data + 10, data, op); // in-place transformation
// data is now {5, 0, -2, 3, -2, -4, 0, 1, -2, -8};
// reduceのサンプル
int data[6] = {1, 0, 2, 2, 1, 3};
int result = thrust::reduce(thrust::host, data, data + 6);
// result == 9
並列計算で重要な演算①〜transformとreduce〜
https://eximia.co/implementing-parallel-reduction-in-cuda/
並列計算で重要な演算②〜イテレータ〜
並列計算で重要な演算②〜イテレータ〜
int main() {
thrust::device_vector<int> int_in(3), int_out(3);
int_in[0] = 0;
int_in[1] = 1;
int_in[2] = 2;
thrust::device_vector<float> float_in(3), float_out(3);
float_in[0] = 0.0f;
float_in[1] = 10.0f;
float_in[2] = 20.0f;
thrust::copy(thrust::make_zip_iterator(thrust::make_tuple(int_in.begin(), float_in.begin())),
thrust::make_zip_iterator(thrust::make_tuple(int_in.end(), float_in.end())),
thrust::make_zip_iterator(thrust::make_tuple(int_out.begin(),float_out.begin())));
// int_out is now [0, 1, 2]
// float_out is now [0.0f, 10.0f, 20.0f]
return 0;
}
並列計算で重要な演算②〜イテレータ〜
struct square : public thrust::unary_function<float,float> {
__device__ float operator()(float x) const {
return x * x;
}
};
int main() {
thrust::device_vector<float> v(4);
v[0] = 1.0f;
v[1] = 2.0f;
v[2] = 3.0f;
v[3] = 4.0f;
float sum_of_squares =
thrust::reduce(thrust::make_transform_iterator(v.begin(), square()),
thrust::make_transform_iterator(v.end(), square()));
std::cout << "sum of squares: " << sum_of_squares << std::endl;
return 0;
}
並列計算で重要な演算③〜sortとscan〜
1 | 1 | 1 | 2 | 2 | 2 | 2 | 3 | 3 | 4 | 4 | … | |
並列計算で重要な演算④〜その他の特殊演算〜
並列計算で重要な演算④〜その他の特殊演算〜
...
const int N = 7;
int A[N] = {1, 3, 3, 3, 2, 2, 1}; // input keys
int B[N] = {9, 8, 7, 6, 5, 4, 3}; // input values
int C[N]; // output keys
int D[N]; // output values
thrust::pair<int*,int*> new_end;
new_end = thrust::reduce_by_key(thrust::host, A, A + N, B, C, D);
// The first four keys in C are now {1, 3, 2, 1} and new_end.first - C is 4.
// The first four values in D are now {9, 21, 9, 3} and new_end.second - D is 4.
点群処理のVoxelGridFilterをThrustで並列化してみる
| | | |
| | | |
| | | |
| | | |
VoxelGridFilterの並列化
VoxelGridFilterの並列化
Thrustを使ったVoxelGridFilterの並列化
// CUDA版VoxelGridFilterのコード抜粋(簡略化しておりこのままでは動かない)
// 入力の点群 points, フィルタ後の出力点群 out_points
// 各点からボクセルキーの計算
thrust::device_vector<Eigen::Vector3i> keys(points.size());
thrust::transform(points.begin(), points.end(), keys.begin(), compute_key_fn);
// ボクセルキーに基づいてソート(ボクセルキーと点群がソートされる)
thrust::device_vector<Eigen::Vector3f> sorted_points = points;
thrust::sort_by_key(keys.begin(), keys.end(), sorted_points.begin());
// 各キー毎の点の和を取ってから点の数で割る
thrust::device_vector<int> counts(points.size());
auto end = thrust::reduce_by_key(
keys.begin(), keys.end(),
thrust::make_zip_iterator(thrust::make_tuple(sorted_point.begin(), thrust::make_constant_iterator(1))),
thrust::make_discard_iterator(),
thrust::make_zip_iterator(thrust::make_tuple(out_points.begin(), counts.begin()));
thrust::transform(out_points.begin(), out_points.end(), counts.begin(), out_points.begin(), div_fn);
計算してみたが、パフォーマンス悪い。。
CPU | Open3D | 32ms |
GPU | Cupoch | 16ms |
Open3D | 7.3ms |
Open3D(GPU版)は簡易VoxelGridFilter
Open3D
Cupoch
元の点群
まとめ