Ant
Ant

Reputation: 1163

How can I get the maximum values of a tensor along a dimension?

I have a 3D tensor and would like to take the max values along the 0th dimension in Libtorch.

I know how to do this in Python (PyTorch) but I'm having trouble doing this in LibTorch.

In LibTorch my code is

auto target_q_T = torch::rand({5, 10, 1});
auto max_q = torch::max({target_q_T}, 0);
std::cout << max_q;

It returns this long, repeating error.

note: candidate: ‘template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const char*)’
  611 |     operator<<(basic_ostream<char, _Traits>& __out, const char* __s)
      |     ^~~~~~~~
/usr/include/c++/11/ostream:611:5: note:   template argument deduction/substitution failed:
/home/iii/tor/m_gym/multiv_normal.cpp:432:18: note:   cannot convert ‘max_q’ (type ‘std::tuple<at::Tensor, at::Tensor>’) to type ‘const char*’
  432 |     std::cout << max_q;
      |                  ^~~~~
In file included from /usr/include/c++/11/istream:39,
                 from /usr/include/c++/11/sstream:38,
                 from /home/iii/tor/m_gym/libtorch/include/c10/macros/Macros.h:246,
                 from /home/iii/tor/m_gym/libtorch/include/c10/core/DeviceType.h:8,
                 from /home/iii/tor/m_gym/libtorch/include/c10/core/Device.h:3,
                 from /home/iii/tor/m_gym/libtorch/include/ATen/core/TensorBody.h:11,
                 from /home/iii/tor/m_gym/libtorch/include/ATen/core/Tensor.h:3,
                 from /home/iii/tor/m_gym/libtorch/include/ATen/Tensor.h:3,
                 from /home/iii/tor/m_gym/libtorch/include/torch/csrc/autograd/function_hook.h:3,
                 from /home/iii/tor/m_gym/libtorch/include/torch/csrc/autograd/cpp_hook.h:2,
                 from /home/iii/tor/m_gym/libtorch/include/torch/csrc/autograd/variable.h:6,
                 from /home/iii/tor/m_gym/libtorch/include/torch/csrc/autograd/autograd.h:3,
                 from /home/iii/tor/m_gym/libtorch/include/torch/csrc/api/include/torch/autograd.h:3,
                 from /home/iii/tor/m_gym/libtorch/include/torch/csrc/api/include/torch/all.h:7,
                 from /home/iii/tor/m_gym/libtorch/include/torch/csrc/api/include/torch/torch.h:3,
                 from /home/iii/tor/m_gym/multiv_normal.cpp:2:
/usr/include/c++/11/ostream:624:5: note: candidate: ‘template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const signed char*)’
  624 |     operator<<(basic_ostream<char, _Traits>& __out, const signed char* __s)
      |     ^~~~~~~~

This is how it works in Python.

target_q_np = torch.rand(5, 10, 1)
max_q = torch.max(target_q_np, 0)
max_q

torch.return_types.max(
values=tensor([[0.8517],
        [0.7526],
        [0.6546],
        [0.9913],
        [0.8521],
        [0.9757],
        [0.9080],
        [0.9376],
        [0.9901],
        [0.7445]]),
indices=tensor([[4],
        [2],
        [3],
        [4],
        [1],
        [0],
        [2],
        [4],
        [4],
        [4]]))

Upvotes: 0

Views: 2463

Answers (2)

trialNerror
trialNerror

Reputation: 3573

If you read the compiler error, it basically tells you that you are trying to print a tuple of two tensors. That's because the C++ code works exactly like the python code and returns the max values and their respective indices (your python code prints exactly that). You need std get to extract the tensors from the tuple :

auto target_q_T = torch::rand({5, 10, 1});
auto max_q = torch::max({target_q_T}, 0);
std::cout << "max: " << std::get<0>(max_q) 
          << "indices: " << std::get<1>(max_q)
          << std::endl;

In C++17 you should also be able to write

auto [max_t, idx_t] = torch::max({target_q_T}, 0);
std::cout << ... ;

Upvotes: 2

Ant
Ant

Reputation: 1163

I never found the equivent use of max in LibTorch like there is in PyTorch so I did a workaround.
The max in LibTorch will take the max from a 1D array so I loop over the indexed array and concatenate the results. Which, in effect returns the same thing as torch.max(target_q_np, 0).

My solution in LibTorch (C++). The array of max values is returned in reverse order as the original tensor, so I flip it.

auto target_q_T = torch::rand({5, 10, 1});

torch::Tensor zero_max;
for (int i=0; i<5; i++) {
    zero_max = torch::cat({torch::max({target_q_T[i]}).unsqueeze(-1), zero_max}, 0);
}
zero_max = zero_max.flip(-1);

Upvotes: 0

Related Questions