Open3D (C++ API)  0.20.0
Loading...
Searching...
No Matches
TorchHelper.h
Go to the documentation of this file.
1// ----------------------------------------------------------------------------
2// - Open3D: www.open3d.org -
3// ----------------------------------------------------------------------------
4// Copyright (c) 2018-2026 www.open3d.org
5// SPDX-License-Identifier: MIT
6// ----------------------------------------------------------------------------
7
8#pragma once
9// https://stackoverflow.com/q/77034039 : False Alarm warnings from PyTorch
10// headers
11#pragma GCC diagnostic ignored "-Warray-bounds"
12#pragma GCC diagnostic ignored "-Wstringop-overflow"
13#include <torch/script.h>
14
15#include <sstream>
16#include <type_traits>
17
18#include "open3d/core/Device.h"
21
22// Macros for checking tensor properties
23#define CHECK_CUDA(x) \
24 do { \
25 TORCH_CHECK(x.is_cuda(), #x " must be a CUDA tensor") \
26 } while (0)
27
28#define CHECK_CONTIGUOUS(x) \
29 do { \
30 TORCH_CHECK(x.is_contiguous(), #x " must be contiguous") \
31 } while (0)
32
33#define CHECK_TYPE(x, type) \
34 do { \
35 TORCH_CHECK(x.dtype() == torch::type, #x " must have type " #type) \
36 } while (0)
37
38#define CHECK_SAME_DEVICE_TYPE(...) \
39 do { \
40 if (!SameDeviceType({__VA_ARGS__})) { \
41 TORCH_CHECK( \
42 false, \
43 #__VA_ARGS__ \
44 " must all have the same device type but got " + \
45 TensorInfoStr({__VA_ARGS__})) \
46 } \
47 } while (0)
48
49#define CHECK_SAME_DTYPE(...) \
50 do { \
51 if (!SameDtype({__VA_ARGS__})) { \
52 TORCH_CHECK(false, \
53 #__VA_ARGS__ \
54 " must all have the same dtype but got " + \
55 TensorInfoStr({__VA_ARGS__})) \
56 } \
57 } while (0)
58
59// Conversion from standard types to torch types
60typedef std::remove_const<decltype(torch::kInt32)>::type TorchDtype_t;
61template <class T>
63 TORCH_CHECK(false, "Unsupported type");
64}
65template <>
67 return torch::kUInt8;
68}
69template <>
71 return torch::kInt8;
72}
73template <>
75 return torch::kInt16;
76}
77template <>
79 return torch::kInt32;
80}
81template <>
83 return torch::kInt64;
84}
85template <>
87 return torch::kFloat32;
88}
89template <>
91 return torch::kFloat64;
92}
93
94// convenience function for comparing standard types with torch types
95template <class T, class TDtype>
96inline bool CompareTorchDtype(const TDtype& t) {
97 return ToTorchDtype<T>() == t;
98}
99
100// convenience function to check if all tensors have the same device type
101inline bool SameDeviceType(std::initializer_list<torch::Tensor> tensors) {
102 if (tensors.size()) {
103 auto device_type = tensors.begin()->device().type();
104 for (const auto& t : tensors) {
105 if (device_type != t.device().type()) {
106 return false;
107 }
108 }
109 }
110 return true;
111}
112
113// convenience function to check if all tensors have the same dtype
114inline bool SameDtype(std::initializer_list<torch::Tensor> tensors) {
115 if (tensors.size()) {
116 auto dtype = tensors.begin()->dtype();
117 for (const auto& t : tensors) {
118 if (dtype != t.dtype()) {
119 return false;
120 }
121 }
122 }
123 return true;
124}
125
126inline std::string TensorInfoStr(std::initializer_list<torch::Tensor> tensors) {
127 std::stringstream sstr;
128 size_t count = 0;
129 for (const auto& t : tensors) {
130 sstr << t.sizes() << " " << t.toString() << " " << t.device();
131 ++count;
132 if (count < tensors.size()) sstr << ", ";
133 }
134 return sstr.str();
135}
136
137// convenience function for creating a tensor for temp memory
138inline torch::Tensor CreateTempTensor(const int64_t size,
139 const torch::Device& device,
140 void** ptr = nullptr) {
141 torch::Tensor tensor = torch::empty(
142 {size}, torch::dtype(ToTorchDtype<uint8_t>()).device(device));
143 if (ptr) {
144 *ptr = tensor.data_ptr<uint8_t>();
145 }
146 return tensor;
147}
148
149// allow_tf32 (Intel XMX/NVIDIA tensor-core reduced-precision GEMM) is only
150// implemented for the SYCL conv-op backend; CPU and CUDA always compute in
151// full precision regardless of this flag. Call once from each CPU/CUDA conv
152// op's entry point to warn the user their request is silently ignored there.
153inline void WarnIfTF32NotSupported(bool allow_tf32) {
154 if (allow_tf32) {
155 open3d::utility::LogWarning(
156 "allow_tf32 is not supported on this backend; computing in "
157 "full float32 precision instead.");
158 }
159}
160
161// Runs the shared SYCL conv-op two-pass temp-memory pattern: call `run_fn`
162// once with temp==nullptr to query the required size, allocate a temp
163// tensor sized by max_temp_mem_MB, then call `run_fn` again to actually run
164// the op. `run_fn` is `(void* temp, size_t& temp_size, size_t&
165// max_temp_size) -> void` and is expected to forward these straight to the
166// underlying `*ComputeFeaturesSYCL` function. Factoring out this pattern
167// avoids duplicating each op's full (15-20 argument) call site twice.
168template <class Fn>
169inline void RunSYCLWithTempMemory(const torch::Device& device,
170 int64_t max_temp_mem_MB,
171 Fn&& run_fn) {
172 void* temp_ptr = nullptr;
173 size_t temp_size = 0;
174 size_t max_temp_size = 0;
175
176 // determine temp_size
177 run_fn(temp_ptr, temp_size, max_temp_size);
178
179 temp_size = std::max(
180 std::min(size_t(max_temp_mem_MB) * 1024 * 1024, max_temp_size),
181 temp_size);
182
183 auto temp_tensor = CreateTempTensor(temp_size, device, &temp_ptr);
184
185 // actually run the operation
186 run_fn(temp_ptr, temp_size, max_temp_size);
187}
188
189inline std::vector<open3d::ml::op_util::DimValue> GetShapeVector(
190 torch::Tensor tensor) {
191 using namespace open3d::ml::op_util;
192
193 std::vector<DimValue> shape;
194 const int rank = tensor.dim();
195 for (int i = 0; i < rank; ++i) {
196 shape.push_back(tensor.size(i));
197 }
198 return shape;
199}
200
202 class TDimX,
203 class... TArgs>
204std::tuple<bool, std::string> CheckShape(torch::Tensor tensor,
205 TDimX&& dimex,
206 TArgs&&... args) {
207 return open3d::ml::op_util::CheckShape<Opt>(GetShapeVector(tensor),
208 std::forward<TDimX>(dimex),
209 std::forward<TArgs>(args)...);
210}
211
212//
213// Macros for checking the shape of Tensors.
214// Usage:
215// {
216// using namespace open3d::ml::op_util;
217// Dim w("w");
218// Dim h("h");
219// CHECK_SHAPE(tensor1, 10, w, h); // checks if the first dim is 10
220// // and assigns w and h based on
221// // the shape of tensor1
222//
223// CHECK_SHAPE(tensor2, 10, 20, h); // this checks if the the last dim
224// // of tensor2 matches the last dim
225// // of tensor1. The first two dims
226// // must match 10, 20.
227// }
228//
229//
230// See "../ShapeChecking.h" for more info and limitations.
231//
232#define CHECK_SHAPE(tensor, ...) \
233 do { \
234 bool cs_success_; \
235 std::string cs_errstr_; \
236 std::tie(cs_success_, cs_errstr_) = CheckShape(tensor, __VA_ARGS__); \
237 TORCH_CHECK(cs_success_, \
238 "invalid shape for '" #tensor "', " + cs_errstr_) \
239 } while (0)
240
241#define CHECK_SHAPE_COMBINE_FIRST_DIMS(tensor, ...) \
242 do { \
243 bool cs_success_; \
244 std::string cs_errstr_; \
245 std::tie(cs_success_, cs_errstr_) = \
246 CheckShape<CSOpt::COMBINE_FIRST_DIMS>(tensor, __VA_ARGS__); \
247 TORCH_CHECK(cs_success_, \
248 "invalid shape for '" #tensor "', " + cs_errstr_) \
249 } while (0)
250
251#define CHECK_SHAPE_IGNORE_FIRST_DIMS(tensor, ...) \
252 do { \
253 bool cs_success_; \
254 std::string cs_errstr_; \
255 std::tie(cs_success_, cs_errstr_) = \
256 CheckShape<CSOpt::IGNORE_FIRST_DIMS>(tensor, __VA_ARGS__); \
257 TORCH_CHECK(cs_success_, \
258 "invalid shape for '" #tensor "', " + cs_errstr_) \
259 } while (0)
260
261#define CHECK_SHAPE_COMBINE_LAST_DIMS(tensor, ...) \
262 do { \
263 bool cs_success_; \
264 std::string cs_errstr_; \
265 std::tie(cs_success_, cs_errstr_) = \
266 CheckShape<CSOpt::COMBINE_LAST_DIMS>(tensor, __VA_ARGS__); \
267 TORCH_CHECK(cs_success_, \
268 "invalid shape for '" #tensor "', " + cs_errstr_) \
269 } while (0)
270
271#define CHECK_SHAPE_IGNORE_LAST_DIMS(tensor, ...) \
272 do { \
273 bool cs_success_; \
274 std::string cs_errstr_; \
275 std::tie(cs_success_, cs_errstr_) = \
276 CheckShape<CSOpt::IGNORE_LAST_DIMS>(tensor, __VA_ARGS__); \
277 TORCH_CHECK(cs_success_, \
278 "invalid shape for '" #tensor "', " + cs_errstr_) \
279 } while (0)
double t
Definition SurfaceReconstructionPoisson.cpp:175
TorchDtype_t ToTorchDtype< int64_t >()
Definition TorchHelper.h:82
TorchDtype_t ToTorchDtype< uint8_t >()
Definition TorchHelper.h:66
std::string TensorInfoStr(std::initializer_list< torch::Tensor > tensors)
Definition TorchHelper.h:126
std::vector< open3d::ml::op_util::DimValue > GetShapeVector(torch::Tensor tensor)
Definition TorchHelper.h:189
TorchDtype_t ToTorchDtype< int16_t >()
Definition TorchHelper.h:74
void WarnIfTF32NotSupported(bool allow_tf32)
Definition TorchHelper.h:153
TorchDtype_t ToTorchDtype< int8_t >()
Definition TorchHelper.h:70
TorchDtype_t ToTorchDtype< double >()
Definition TorchHelper.h:90
bool SameDtype(std::initializer_list< torch::Tensor > tensors)
Definition TorchHelper.h:114
bool SameDeviceType(std::initializer_list< torch::Tensor > tensors)
Definition TorchHelper.h:101
std::remove_const< decltype(torch::kInt32)>::type TorchDtype_t
Definition TorchHelper.h:60
TorchDtype_t ToTorchDtype()
Definition TorchHelper.h:62
void RunSYCLWithTempMemory(const torch::Device &device, int64_t max_temp_mem_MB, Fn &&run_fn)
Definition TorchHelper.h:169
torch::Tensor CreateTempTensor(const int64_t size, const torch::Device &device, void **ptr=nullptr)
Definition TorchHelper.h:138
std::tuple< bool, std::string > CheckShape(torch::Tensor tensor, TDimX &&dimex, TArgs &&... args)
Definition TorchHelper.h:204
TorchDtype_t ToTorchDtype< int32_t >()
Definition TorchHelper.h:78
bool CompareTorchDtype(const TDtype &t)
Definition TorchHelper.h:96
TorchDtype_t ToTorchDtype< float >()
Definition TorchHelper.h:86
int size
Definition FilePCD.cpp:41
int count
Definition FilePCD.cpp:43
char type
Definition FilePCD.cpp:42
Definition ShapeChecking.h:16
CSOpt
Check shape options.
Definition ShapeChecking.h:405