11 #include <tbb/task_group.h>
14 #include <unordered_map>
22 template <
class TReal,
30 min_sqr_dist_to_center_(
std::numeric_limits<TReal>::
max()),
32 static_assert(POS_FN !=
MAX,
"MAX is not allowed for point positions");
33 static_assert(FEAT_FN !=
CENTER,
34 "CENTER is not allowed for feature vectors");
37 template <
class Derived,
class Derived2,
class Derived3>
38 inline void AddPoint(
const Eigen::MatrixBase<Derived>& pos,
39 const Eigen::MatrixBase<Derived2>& voxel_center,
40 const Eigen::ArrayBase<Derived3>& feat) {
41 bool new_nearest_neighbor =
false;
44 sqr_d = (voxel_center - pos).squaredNorm();
45 if (sqr_d < min_sqr_dist_to_center_) {
46 new_nearest_neighbor =
true;
47 min_sqr_dist_to_center_ = sqr_d;
51 position_ += pos.array();
54 }
else if (POS_FN ==
CENTER) {
55 if (count_ == 0) position_ = voxel_center;
59 features_.resizeLike(feat);
66 }
else if (FEAT_FN ==
MAX) {
67 features_ = features_.max(feat);
72 inline Eigen::Array<TReal, 3, 1>
Position()
const {
74 return position_ / count_;
81 inline Eigen::Array<TFeat, Eigen::Dynamic, 1>
Features()
const {
83 return features_ / count_;
90 inline int Count()
const {
return count_; }
94 TReal min_sqr_dist_to_center_;
95 Eigen::Array<TReal, 3, 1> position_;
96 Eigen::Array<TFeat, Eigen::Dynamic, 1> features_;
99 template <
class TReal,
107 min_sqr_dist_to_center_(
std::numeric_limits<TReal>::
max()),
109 static_assert(POS_FN !=
MAX,
"MAX is not allowed for point positions");
110 static_assert(FEAT_FN !=
CENTER,
111 "CENTER is not allowed for feature vectors");
114 template <
class Derived,
class Derived2,
class Derived3>
115 inline void AddPoint(
const Eigen::MatrixBase<Derived>& pos,
116 const Eigen::MatrixBase<Derived2>& voxel_center,
117 const Eigen::ArrayBase<Derived3>& feat,
119 bool new_nearest_neighbor =
false;
122 sqr_d = (voxel_center - pos).squaredNorm();
123 if (sqr_d < min_sqr_dist_to_center_) {
124 new_nearest_neighbor =
true;
125 min_sqr_dist_to_center_ = sqr_d;
130 position_ += pos.array();
133 }
else if (POS_FN ==
CENTER) {
134 if (count_ == 0) position_ = voxel_center;
138 features_.resizeLike(feat);
146 }
else if (FEAT_FN ==
MAX) {
148 index_.resizeLike(feat);
159 }
else if (FEAT_FN ==
MAX) {
160 for (
int i = 0; i < features_.rows(); ++i) {
161 if (feat(i) > features_(i)) {
162 features_(i) = feat(i);
170 inline Eigen::Array<TReal, 3, 1>
Position()
const {
172 return position_ / count_;
179 inline Eigen::Array<TFeat, Eigen::Dynamic, 1>
Features()
const {
181 return features_ / count_;
188 inline int Count()
const {
return count_; }
190 inline Eigen::Array<size_t, Eigen::Dynamic, 1>
Index()
const {
196 TReal min_sqr_dist_to_center_;
197 Eigen::Array<TReal, 3, 1> position_;
198 Eigen::Array<TFeat, Eigen::Dynamic, 1> features_;
199 Eigen::Array<size_t, Eigen::Dynamic, 1> index_;
205 const size_t num_positions,
206 const T*
const positions,
207 const T voxel_size) {
208 typedef Eigen::Array<double, 3, 1> Vec3_t;
209 if (num_positions == 0) {
213 Vec3_t bb_min, bb_max;
214 bb_min << positions[0], positions[1], positions[2];
217 Vec3_t voxel_size3(voxel_size, voxel_size, voxel_size);
219 for (
size_t i = 1; i < num_positions; ++i) {
220 Vec3_t pos(positions[i * 3 + 0], positions[i * 3 + 1],
221 positions[i * 3 + 2]);
222 bb_min = bb_min.min(pos);
223 bb_max = bb_max.max(pos);
227 bb_min /= voxel_size3;
228 bb_min = bb_min.floor() * voxel_size3;
229 bb_max /= voxel_size3;
230 bb_max = bb_max.ceil() * voxel_size3;
236 err =
"voxel_size is too small\n";
247 template <
class TDerived>
249 const Eigen::ArrayBase<TDerived>& pos,
250 const typename TDerived::Scalar& inv_voxel_size) {
251 typedef typename TDerived::Scalar Scalar_t;
252 Eigen::Array<Scalar_t, 3, 1> ref_coord = pos * inv_voxel_size;
255 voxel_index = ref_coord.floor().template cast<int>();
260 template <
class TReal,
class TFeat,
class ACCUMULATOR,
class OUTPUT_ALLOCATOR>
262 const TReal*
const inp_positions,
264 const TFeat* inp_features,
266 OUTPUT_ALLOCATOR& output_allocator) {
270 output_allocator.AllocPooledPositions(&out_pos_ptr, 0);
271 output_allocator.AllocPooledFeatures(&out_feat_ptr, 0, in_channels);
275 typedef Eigen::Array<TReal, 3, 1> Vec3_t;
276 typedef Eigen::Array<TFeat, Eigen::Dynamic, 1> FeatureVec_t;
280 voxelindex_to_accpoint;
284 TReal inv_voxel_size = 1 / voxel_size;
285 TReal half_voxel_size = 0.5 * voxel_size;
286 for (
size_t i = 0; i < num_inp; ++i) {
287 Eigen::Map<const Vec3_t> pos(inp_positions + i * 3);
291 voxel_center << voxel_index(0) * voxel_size + half_voxel_size,
292 voxel_index(1) * voxel_size + half_voxel_size,
293 voxel_index(2) * voxel_size + half_voxel_size;
295 Eigen::Map<const FeatureVec_t> feat(inp_features + in_channels * i,
297 voxelindex_to_accpoint[voxel_index].AddPoint(
298 pos.matrix(), voxel_center.matrix(), feat);
301 const size_t num_out = voxelindex_to_accpoint.size();
305 output_allocator.AllocPooledPositions(&out_pos_ptr, num_out);
306 output_allocator.AllocPooledFeatures(&out_feat_ptr, num_out, in_channels);
309 for (
const auto point : voxelindex_to_accpoint) {
310 Vec3_t pos =
point.second.Position();
311 Eigen::Map<Vec3_t> out_pos(out_pos_ptr + i * 3);
314 Eigen::Map<FeatureVec_t> out_feat(out_feat_ptr + i * in_channels,
316 out_feat =
point.second.Features();
323 template <
class TReal,
class TFeat,
class ACCUMULATOR, AccumulationFn FEAT_FN>
326 const TReal*
const inp_positions,
328 const TFeat*
const inp_features,
330 const TReal*
const pooled_positions,
331 const TFeat*
const pooled_features_gradient,
336 memset(features_backprop, 0,
sizeof(TFeat) * num_inp * in_channels);
338 typedef Eigen::Array<TReal, 3, 1> Vec3_t;
339 typedef Eigen::Array<TFeat, Eigen::Dynamic, 1> FeatureVec_t;
341 Vec3_t voxel_size3(voxel_size, voxel_size, voxel_size);
344 tbb::task_group task_group;
348 voxelindex_to_accpoint;
353 TReal inv_voxel_size = 1 / voxel_size;
354 TReal half_voxel_size = 0.5 * voxel_size;
355 for (
size_t i = 0; i < num_inp; ++i) {
356 Eigen::Map<const Vec3_t> pos(inp_positions + i * 3);
360 voxel_center << voxel_index(0) * voxel_size + half_voxel_size,
361 voxel_index(1) * voxel_size + half_voxel_size,
362 voxel_index(2) * voxel_size + half_voxel_size;
364 Eigen::Map<const FeatureVec_t> feat(inp_features + in_channels * i,
366 voxelindex_to_accpoint[voxel_index].AddPoint(
367 pos.matrix(), voxel_center.matrix(), feat, i);
373 voxelindex_to_gradindex;
377 TReal inv_voxel_size = 1 / voxel_size;
378 for (
size_t i = 0; i < num_pooled; ++i) {
379 Eigen::Map<const Vec3_t> pos(pooled_positions + i * 3);
383 voxelindex_to_gradindex[voxel_index] = i;
391 TReal inv_voxel_size = 1 / voxel_size;
392 for (
size_t i = 0; i < num_inp; ++i) {
393 Eigen::Map<const Vec3_t> pos(inp_positions + i * 3);
397 Eigen::Map<FeatureVec_t> feat_bp(
398 features_backprop + in_channels * i, in_channels);
400 size_t grad_idx = voxelindex_to_gradindex[voxel_index];
401 int count = voxelindex_to_accpoint[voxel_index].Count();
402 Eigen::Map<const FeatureVec_t> grad(
403 pooled_features_gradient + in_channels * grad_idx,
405 feat_bp = grad /
count;
410 for (
const auto point : voxelindex_to_accpoint) {
411 size_t idx =
point.second.Index()(0);
412 Eigen::Map<FeatureVec_t> feat_bp(
413 features_backprop + in_channels * idx, in_channels);
415 size_t grad_idx = voxelindex_to_gradindex[
point.first];
416 Eigen::Map<const FeatureVec_t> grad(
417 pooled_features_gradient + in_channels * grad_idx,
423 if (FEAT_FN ==
MAX) {
424 for (
const auto point : voxelindex_to_accpoint) {
425 size_t grad_idx = voxelindex_to_gradindex[
point.first];
426 Eigen::Map<const FeatureVec_t> grad(
427 pooled_features_gradient + in_channels * grad_idx,
429 for (
int i = 0; i < in_channels; ++i) {
430 size_t idx =
point.second.Index()(i);
431 Eigen::Map<FeatureVec_t> feat_bp(
432 features_backprop + in_channels * idx, in_channels);
433 feat_bp(i) = grad(i);
483 template <
class TReal,
class TFeat,
class OUTPUT_ALLOCATOR>
485 const TReal*
const inp_positions,
487 const TFeat* inp_features,
489 OUTPUT_ALLOCATOR& output_allocator,
492 #define CALL_TEMPLATE(POS_FN, FEAT_FN) \
493 if (POS_FN == position_fn && FEAT_FN == feature_fn) { \
494 _VoxelPooling<TReal, TFeat, \
495 Accumulator<TReal, TFeat, POS_FN, FEAT_FN>>( \
496 num_inp, inp_positions, in_channels, inp_features, voxel_size, \
528 template <
class TReal,
class TFeat>
531 const TReal*
const inp_positions,
533 const TFeat*
const inp_features,
535 const TReal*
const pooled_positions,
536 const TFeat*
const pooled_features_gradient,
540 #define CALL_TEMPLATE(POS_FN, FEAT_FN) \
541 if (POS_FN == position_fn && FEAT_FN == feature_fn) { \
542 _VoxelPoolingBackprop< \
544 AccumulatorBackprop<TReal, TFeat, POS_FN, FEAT_FN>, FEAT_FN>( \
545 features_backprop, num_inp, inp_positions, in_channels, \
546 inp_features, num_pooled, pooled_positions, \
547 pooled_features_gradient, voxel_size); \
#define CALL_TEMPLATE(POS_FN, FEAT_FN)
Eigen::Array< TFeat, Eigen::Dynamic, 1 > Features() const
void AddPoint(const Eigen::MatrixBase< Derived > &pos, const Eigen::MatrixBase< Derived2 > &voxel_center, const Eigen::ArrayBase< Derived3 > &feat, const size_t idx)
Eigen::Array< TReal, 3, 1 > Position() const
Eigen::Array< size_t, Eigen::Dynamic, 1 > Index() const
Eigen::Array< TFeat, Eigen::Dynamic, 1 > Features() const
Eigen::Array< TReal, 3, 1 > Position() const
void AddPoint(const Eigen::MatrixBase< Derived > &pos, const Eigen::MatrixBase< Derived2 > &voxel_center, const Eigen::ArrayBase< Derived3 > &feat)
Helper functions for the ml ops.
bool CheckVoxelSize(std::string &err, const size_t num_positions, const T *const positions, const T voxel_size)
Function for debugging. Checks if the voxel size is too small.
void VoxelPoolingBackprop(TFeat *features_backprop, size_t num_inp, const TReal *const inp_positions, int in_channels, const TFeat *const inp_features, size_t num_pooled, const TReal *const pooled_positions, const TFeat *const pooled_features_gradient, TReal voxel_size, AccumulationFn position_fn, AccumulationFn feature_fn)
void _VoxelPoolingBackprop(TFeat *features_backprop, size_t num_inp, const TReal *const inp_positions, int in_channels, const TFeat *const inp_features, size_t num_pooled, const TReal *const pooled_positions, const TFeat *const pooled_features_gradient, TReal voxel_size)
void _VoxelPooling(size_t num_inp, const TReal *const inp_positions, int in_channels, const TFeat *inp_features, TReal voxel_size, OUTPUT_ALLOCATOR &output_allocator)
utility::MiniVec< int, 3 > ComputeVoxelIndex(const TVecf &pos, const typename TVecf::Scalar_t &inv_voxel_size)
void VoxelPooling(size_t num_inp, const TReal *const inp_positions, int in_channels, const TFeat *inp_features, TReal voxel_size, OUTPUT_ALLOCATOR &output_allocator, AccumulationFn position_fn, AccumulationFn feature_fn)
Generic file read and write utility for python interface.
Eigen::Matrix< Index, 3, 1 > Vector3i