https://mooseframework.inl.gov
LibtorchUtils.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #ifdef MOOSE_LIBTORCH_ENABLED
11 
12 #include "LibtorchUtils.h"
13 
14 #include <algorithm>
15 #include <functional>
16 #include <numeric>
17 
18 namespace LibtorchUtils
19 {
20 
21 namespace
22 {
23 
24 template <typename DataType>
25 torch::TensorOptions
26 tensorOptions()
27 {
28  if constexpr (std::is_same<DataType, double>::value)
29  return torch::TensorOptions().dtype(at::kDouble);
30  else if constexpr (std::is_same<DataType, float>::value)
31  return torch::TensorOptions().dtype(at::kFloat);
32  else
33  static_assert(Moose::always_false<DataType>,
34  "Tensor conversion is not implemented for the given data type!");
35 }
36 
37 template <typename DataType>
38 void
39 checkTensorShape(const std::vector<DataType> & vector, c10::IntArrayRef sizes)
40 {
41  const auto expected_numel =
42  std::accumulate(sizes.begin(), sizes.end(), int64_t{1}, std::multiplies<int64_t>());
43 
44  if (expected_numel != cast_int<int64_t>(vector.size()))
45  mooseError("The requested tensor shape is incompatible with the vector size.");
46 }
47 
48 } // namespace
49 
50 template <typename DataType>
51 torch::Tensor
52 vectorToTensorCopy(const std::vector<DataType> & vector, c10::IntArrayRef sizes)
53 {
54  checkTensorShape(vector, sizes);
55 
56  const auto options = tensorOptions<DataType>();
57  auto tensor = torch::empty(sizes, options);
58 
59  if (!vector.empty())
60  std::copy(vector.begin(), vector.end(), tensor.template data_ptr<DataType>());
61 
62  return tensor;
63 }
64 
65 // Explicitly instantiate for DataType=Real
66 template torch::Tensor vectorToTensorCopy<Real>(const std::vector<Real> & vector,
67  c10::IntArrayRef sizes);
68 
69 template <typename DataType>
70 void
71 vectorToTensor(const std::vector<DataType> & vector, torch::Tensor & tensor, const bool detach)
72 {
73  tensor = vectorToTensorCopy(vector, {long(vector.size()), 1});
74 
75  if (detach)
76  tensor = tensor.detach();
77 }
78 
79 // Explicitly instantiate for DataType=Real
80 template void
81 vectorToTensor<Real>(const std::vector<Real> & vector, torch::Tensor & tensor, const bool detach);
82 
83 template <typename DataType>
84 torch::Tensor
85 vectorToTensorView(std::vector<DataType> & vector, c10::IntArrayRef sizes)
86 {
87  checkTensorShape(vector, sizes);
88 
89  const auto options = tensorOptions<DataType>();
90  if (vector.empty())
91  return torch::empty(sizes, options);
92 
93  return torch::from_blob(vector.data(), sizes, options);
94 }
95 
96 // Explicitly instantiate for DataType=Real
97 template torch::Tensor vectorToTensorView<Real>(std::vector<Real> & vector, c10::IntArrayRef sizes);
98 
99 void
100 moveToLibtorchDevice(torch::Tensor & tensor, const torch::DeviceType device_type)
101 {
102  tensor = tensor.to(device_type);
103 }
104 
105 torch::Tensor
106 toCPUContiguous(const torch::Tensor & tensor)
107 {
108  // CPU accessors can handle strides, but data_ptr()-based reads require dense logical order.
109  return tensor.detach().to(tensor.options().device(at::kCPU)).contiguous();
110 }
111 
112 template <typename DataType>
113 void
114 tensorToVector(torch::Tensor & tensor, std::vector<DataType> & vector)
115 {
116  try
117  {
118  tensor.data_ptr<DataType>();
119  }
120  catch (const c10::Error & e)
121  {
122  mooseError(
123  "Cannot cast tensor values to", MooseUtils::prettyCppType<DataType>(), "!\n", e.msg());
124  }
125 
126  const auto & sizes = tensor.sizes();
127 
128  long int max_size = 0;
129  for (const auto & dim_size : sizes)
130  // We do this comparison because XCode complains if we use std::max
131  max_size = dim_size > max_size ? dim_size : max_size;
132 
133  mooseAssert(max_size == tensor.numel(), "The given tensor should be one-dimensional!");
134  vector = {tensor.data_ptr<DataType>(), tensor.data_ptr<DataType>() + tensor.numel()};
135 }
136 
137 // Explicitly instantiate for DataType=Real
138 template void tensorToVector<Real>(torch::Tensor & tensor, std::vector<Real> & vector);
139 
140 } // LibtorchUtils namespace
141 
142 #endif
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
torch::Tensor vectorToTensorView(std::vector< DataType > &vector, c10::IntArrayRef sizes)
Utility function that creates a non-owning tensor view of a standard vector.
Definition: LibtorchUtils.C:85
torch::Tensor vectorToTensorCopy(const std::vector< DataType > &vector, c10::IntArrayRef sizes)
Utility function that creates an owning tensor copy of a standard vector.
Definition: LibtorchUtils.C:52
void tensorToVector(torch::Tensor &tensor, std::vector< DataType > &vector)
Utility function that converts a torch::Tensor to a standard vector.
torch::Tensor toCPUContiguous(const torch::Tensor &tensor)
Return a detached contiguous CPU copy of a tensor.
void vectorToTensor(const std::vector< DataType > &vector, torch::Tensor &tensor, const bool detach=false)
Utility function that converts a standard vector to a torch::Tensor.
Definition: LibtorchUtils.C:71
template void vectorToTensor< Real >(const std::vector< Real > &vector, torch::Tensor &tensor, const bool detach)
template torch::Tensor vectorToTensorCopy< Real >(const std::vector< Real > &vector, c10::IntArrayRef sizes)
template torch::Tensor vectorToTensorView< Real >(std::vector< Real > &vector, c10::IntArrayRef sizes)
template void tensorToVector< Real >(torch::Tensor &tensor, std::vector< Real > &vector)
void moveToLibtorchDevice(torch::Tensor &tensor, const torch::DeviceType device_type)
Move a tensor to the configured libtorch device.