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

问题描述 投票:0回答:1

我正在尝试在 C++ 中围绕

Eigen::Tensor
对象创建一个包装器。这个想法是基于提供的数组在张量上创建一个碎片视图,该数组要么指定要碎片的行,要么指定
-1
表示跳过此维度的碎片操作:

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 文档中的芯片文档

我最初的方法是简单地使用循环:

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
模板方法的实例,直到指定的最大维度,在本例中为 3。为什么会创建这么多实例呢? 这是否被认为是解决上述问题的干净方法? 代码可以在此处的编译器资源管理器中运行

c++ c++17 eigen tensor eigen3
1个回答
0
投票

问题的出现是因为 N 在此实现中没有可靠地递减,这导致编译器创建了无限多个 recursiveChip 函数的实例。减少输入数组以仅包含芯片旁边的尺寸解决了问题:

#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;
}
© www.soinside.com 2019 - 2024. All rights reserved.