Equivalence of slicing tensor in Pytorch/ATen C++
Asked Answered
S

2

13

In Python given a 2-D tensor, we can use tensor[:,:2] to slice the a 2x2 matrix of the first two elements in the top left of the matrix, e.g. :

x = torch.tensor([[-1.4673,  0.9980, -2.1427, -1.1798, -0.0646, -0.2635, -2.8930, -0.2563,
          0.4559, -0.7947, -0.4540,  3.3224,  0.2295,  5.5568, -8.0451, -2.4529,
          4.8724,  2.1640,  3.3255,  0.6693, -1.2362,  4.4713, -3.5547, -0.0528,
          0.1031, -1.2472, -1.6014,  1.8134],
        [ 2.1636, -1.1497, -5.0298,  2.8261, -0.5684,  0.6389,  2.9009, -5.1609,
          1.7358, -3.1819, -0.9877,  5.5598,  6.7142,  4.5704, -1.2683, -5.3046,
          3.0454,  3.2757, -3.2541,  3.6619, -3.6391, -0.2002,  5.7175,  5.7130,
          0.6632, -0.0744, -0.3502,  4.8116]])

y, z = x[:,:2].chunk(2,1)

print(y)

print(z)

[out]:

tensor([[-1.4673],
        [ 2.1636]])
tensor([[ 0.9980],
        [-1.1497]])

What is right way to do it in C++ for PyTorch's ATen particularly?

For e.g. in the LSTM, there is the gate.chunk(4,1) function at https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/native/RNN.cpp#L253

If I want to do a gate[:,:2].chunk(2,1) to extract different parts of the gates, e.g. auto partial_gates = gates[:,:2].chunk(4, 1);, how can it be done?

template <typename cell_params>
struct LSTMCell : Cell<std::tuple<Tensor, Tensor>, cell_params> {
  using hidden_type = std::tuple<Tensor, Tensor>;
  hidden_type operator()(const Tensor& input, const hidden_type& hidden, const cell_params& params) const override {
    auto hx = std::get<0>(hidden);
    auto cx = std::get<1>(hidden);

    if (input.is_cuda()) {
      auto igates = params.matmul_ih(input);
      auto hgates = params.matmul_hh(hx);
      auto result = at::_thnn_fused_lstm_cell(igates, hgates, cx, params.b_ih, params.b_hh);
      // Slice off the workspace argument (it's needed only for AD).
      return std::make_tuple(std::get<0>(result), std::get<1>(result));
    }

    auto gates = params.linear_ih(input) + params.linear_hh(hx);
    auto chunked_gates = gates.chunk(4, 1);

    auto partial_gates = gates[:,:2].chunk(4, 1);

    auto ingate = chunked_gates[0].sigmoid();
    auto forgetgate = chunked_gates[1].sigmoid();
    auto cellgate = chunked_gates[2].tanh();
    auto outgate = chunked_gates[3].sigmoid();

    auto cy = (forgetgate * cx) + (ingate * cellgate);
    auto hy = outgate * cy.tanh();

    return std::make_tuple(hy, cy);
  }
};
Soapbark answered 21/6, 2019 at 6:34 Comment(1)
the best place to find information about libtorch unfortunantly is not here but on discuss pytorch discuss.pytorch.org . Lost days to figure this out.Urethra
S
4

It's .narrow() from https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/native/TensorShape.cpp#L364

auto partial_gates = gates.narrow(1,0,2).chunk(4, 1);
Soapbark answered 21/6, 2019 at 20:45 Comment(0)
U
12

1. You can also use .slice

Tensor::slice(int64_t dim, int64_t start, int64_t end, int64_t step)

auto partial_gates = gates.slice(1, 0, 3).chunk(4, 1); 

2. Pytorch 1.5 using Tensor::index and Tensor::index_put_

using namespace torch::indexing;
auto partial_gates = gates.index({"...", Slice(None, 2)}).chunk(4, 1); 

Also supports multimensional indexing

General translation for Tensor::index and Tensor::index_put_

Python             C++ (assuming `using namespace torch::indexing`)
-------------------------------------------------------------------
0                  0
None               None
...                "..." or Ellipsis
:                  Slice()
start:stop:step    Slice(start, stop, step)
True / False       true / false
[[1, 2]]           torch::tensor({{1, 2}})
Urethra answered 4/2, 2020 at 14:36 Comment(0)
S
4

It's .narrow() from https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/native/TensorShape.cpp#L364

auto partial_gates = gates.narrow(1,0,2).chunk(4, 1);
Soapbark answered 21/6, 2019 at 20:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.