c++ 是否可以根据数组中指定的值递归地对特征Tensor进行切片?

mnowg1ta  于 2023-11-19  发布在  其他
关注(0)|答案(1)|浏览(101)

我试图在c++中创建一个Eigen::Tensor对象的 Package 器。其想法是基于提供的数组在Tensor上创建一个chipped视图,该视图指定要chip的行沿着或-1表示跳过此维度的chipping操作:

Eigen::Tensor<double, 3> tensor(4, 3, 2);
std::vector<int> indices = {3, -1, 1};

字符串
想要的结果就像

auto view = tensor.chip(1, 2).chip(3, 0)


获取最后一个维度中的第一行和第一个维度中的第三行。(参见Eigen::Tensor文档中的documentation of chip
我最初的方法是简单地使用一个循环:

template<typename T, int N>
auto createChippedAndSlicedView(Eigen::Tensor<T, N>& tensor, const Indices<N>& indices) {
    auto view = tensor;
    for (int i = N - 1; i >= 0; --i) {
        if (indices.chip_indices[i] != -1) {
            view = view.chip(indices.chip_indices[i], i);
        }
    }
    return view;
}


但这并不起作用,因为我们在每次迭代中都要改变我们试图分配给view的维度,然后我试图递归地实现它:

#include <Eigen/Dense>
#include <unsupported/Eigen/CXX11/Tensor>
#include <iostream>
#include <vector>

template<typename TensorType>
auto chipTensorRecursive(TensorType &tensor, const std::vector<int> &indices, size_t dim) {
    if (dim >= indices.size()) {
        return tensor;
    }
    if (indices[dim] == -1) {
        return chipTensorRecursive(tensor, indices, dim + 1);
    } else {
        auto chippedTensor = tensor.chip(indices[dim], dim);
        return chipTensorRecursive(chippedTensor, indices, dim + 1);
    }
}
template<typename TensorType>
auto chipTensor(TensorType &tensor, const std::vector<int> &indices) {
    return chipTensorRecursive(tensor, indices, 0);
}
int main() {
    Eigen::Tensor<double, 3> tensor(4, 3, 2);
    std::vector<int> indices = {1, -1, 1};
    tensor.setValues({{{ 0,  1}, { 2,  3}, { 4,  5}}, 
                      {{ 6,  7}, { 8,  9}, {10, 11}}, 
                      {{12, 13}, {14, 15}, {16, 17}}, 
                      {{18, 19}, {20, 21}, {22, 23}}});
    auto result = chipTensor(tensor, indices);
    std::cout << "Result: " << result << std::endl;
    return 0;
}


但这会产生内部特征误差

In file included from /usr/include/eigen3/unsupported/Eigen/CXX11/Tensor:72,
                 from test.cpp:2:
/usr/include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorInitializer.h: In instantiation of ‘struct Eigen::internal::Initializer<Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::Tensor<double, 3> > > > >, -893>’:
/usr/include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorInitializer.h:29:53:   recursively required from ‘struct Eigen::internal::Initializer<Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::Tensor<double, 3> > > > >, -2>’
/usr/include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorInitializer.h:29:53:   required from ‘struct Eigen::internal::Initializer<Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::Tensor<double, 3> > > > >, -1>’
/usr/include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h:1006:34:   required from ‘class Eigen::TensorBase<Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::Tensor<double, 3> > > > >, 1>’
/usr/include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorChipping.h:80:7:   required from ‘class Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::TensorChippingOp<-1, Eigen::Tensor<double, 3> > > > >’
test.cpp:19:35:   recursively required from ‘auto chipTensorRecursive(TensorType&, const std::vector<int>&, size_t) [with TensorType = Eigen::TensorChippingOp<-1, Eigen::Tensor<double, 3> >]’
test.cpp:19:35:   required from ‘auto chipTensorRecursive(TensorType&, const std::vector<int>&, size_t) [with TensorType = Eigen::Tensor<double, 3>]’
test.cpp:25:31:   required from ‘auto chipTensor(TensorType&, const std::vector<int>&) [with TensorType = Eigen::Tensor<double, 3>]’
test.cpp:42:29:   required from here
/usr/include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorInitializer.h:29:53: fatal error: template instantiation depth exceeds maximum of 900 (use ‘-ftemplate-depth=’ to increase the maximum)
   29 |     typename Initializer<Derived, N - 1>::InitList> InitList;
      |                                                     ^~~~~~~~
compilation terminated.


说明它已经达到了可以创建的模板的最大限制。根据我的理解,编译器应该尝试为每个维度创建一个chipTensorRecursive模板方法的示例,直到最大指定的维度,在这个例子中是三个。为什么会有这么多的示例被创建?这会被认为是解决上述问题的干净方法吗?The code can be run in the compiler explorer here

wkyowqbh

wkyowqbh1#

问题的出现是因为在这个实现中N没有可靠地递减,这导致编译器创建了我们的recursiveChip函数的无限多个示例。减少输入数组,使其只包含要chip的维度,解决了这个问题:

#include <Eigen/Dense>
#include <unsupported/Eigen/CXX11/Tensor>
#include <iostream>
#include <vector>
#include <utility>

template<typename TensorType, size_t N, size_t M=N>
auto chipTensorRecursive(TensorType &tensor, const std::array<std::pair<int, int>, N> &chips) {
    if constexpr (M == 0) {
        return tensor;
    } else {
        int dim = chips[M - 1].first;  // Use N-1 as index
        int row = chips[M - 1].second;

        auto chippedTensor = tensor.chip(row, dim);
        return chipTensorRecursive<decltype(chippedTensor), N, M-1>(chippedTensor, chips);
    }
}

template<typename TensorType, size_t N>
auto chipTensor(TensorType &tensor, const std::array<std::pair<int, int>, N> &chips) {
    return chipTensorRecursive<TensorType, N>(tensor, chips);
}

int main() {
    Eigen::Tensor<double, 3> tensor(4, 3, 2);
    std::array<std::pair<int, int>, 2> chips = {{{0, 1}, {2, 1}}};
    tensor.setValues({{{0, 1}, {2, 3}, {4, 5}},
                      {{6, 7}, {8, 9}, {10, 11}},
                      {{12, 13}, {14, 15}, {16, 17}},
                      {{18, 19}, {20, 21}, {22, 23}}});
    auto result = chipTensor(tensor, chips);
    std::cout << "Result: " << result << std::endl;
    return 0;
}

字符串

相关问题