Eigen3 tensor slices without making a copy of the data
Asked Answered
C

2

7

I have been testing the Tensor module from Eigen3 for a new project. Even when the module is not yet finished, it seems to have most of the functionality that I need.

But there is one part that I quite not get. Whenever I have a big Tensor and I want to extract a slice from it, Eigen makes a copy of the data.

Is there a way to not copy the data, but instead point to the original data block in the slice?

For example if I do:

Tensor<float, 3> A(100,1000,1000); A.setZero();

Eigen::array<int, 3> offsets = {0, 0, 0};
Eigen::array<int, 3> extents = {2, 2, 2};

Tensor<float, 3> c = A.slice(offsets, extents);
A(0,0,0) = 1.0;

cerr << c << endl;

But the first element of "c" is still zero, instead of mapping to the modified "A(0,0,0)" data block.

Casting answered 15/10, 2018 at 18:19 Comment(4)
Maybe TensorRef is an option. The implementation looks quite inefficient, though (using dynamic polymorphism).Woad
Thanks for your answer. I know it is possible with Blitz++, which (sadly) is not as efficient as Eigen3 with array operations in my tests.Casting
Is just using auto c = A.slice(offsets, extents); an option?Woad
Using "auto" seems to keep a reference to the original block, but I cannot use the parenthesis operator in "c". So I can print c as a matrix., I suspect it is making a copy of the data block in A every time I call err<<c<<endl;Casting
C
1

You can use a TensorMap to create a tensor based on shared memory space of your slice. However this only works if your slice occupies contiguous portion of the data array. Otherwise you would need to do some tensor arithmetic to figure out the begin and end 1d indices of various parts of your single slice.

TensorMap<Tensor<float, 3, RowMajor> > row_major(data, ...);
Child answered 12/1, 2019 at 5:47 Comment(0)
T
0

Now, this works out of the box:

using Eigen::Tensor;

Tensor<float, 3> img(4, 4, 3);
    img.setConstant(1);
    img.slice(array<int, 3>{0, 0, 0}, array<int, 3>{2, 2, 3}).setZero();
    Tensor<float, 3> patch(2, 2, 3);
    patch.setRandom();
    img.slice(array<int, 3>{2, 2, 0}, array<int, 3>{2, 2, 3}) = patch;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            std::cout << "(";
            for (int c = 0; c < 3; c++) {
                std::cout << img(i, j, c) << ", ";
            }
            std::cout << ") ";
        }
        std::cout << std::endl;
    }
(0, 0, 0, ) (0, 0, 0, ) (1, 1, 1, ) (1, 1, 1, )
(0, 0, 0, ) (0, 0, 0, ) (1, 1, 1, ) (1, 1, 1, )
(1, 1, 1, ) (1, 1, 1, ) (0.00576293, 0.909376, 0.049831, ) (0.168537, 0.634598, 0.603522, )
(1, 1, 1, ) (1, 1, 1, ) (0.288325, 0.286939, 0.183521, ) (0.808391, 0.085356, 0.00413311, )
Tarnish answered 13/2 at 14:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.