21 static constexpr Index
bytes = Index(
sizeof(
float));
22 static constexpr const char*
name =
"FP32";
31 static constexpr const char*
name =
"BF16";
39 static constexpr Index
bytes = Index(
sizeof(int8_t));
40 static constexpr const char*
name =
"INT8";
43template<
Type... Supported,
typename F>
49 if (!matched && t == Supported)
55 throw_if(!matched,
"visit_type: unsupported Type value");
58template<
Type... Supported,
typename F>
61 visit_type<Supported...>(t_in, [&]<
typename TIn>()
63 visit_type<Supported...>(t_out, [&]<
typename TOut>()
65 f.template operator()<TIn, TOut>();
81 throw runtime_error(
string(caller) +
": Type::Auto must be resolved before tensor use.");
104 throw_if(value > Index(numeric_limits<int>::max()) || value < Index(numeric_limits<int>::min()),
105 "to_int: value {} exceeds int range.", value);
106 return static_cast<int>(value);
108inline float to_type(Index value) {
return static_cast<float>(value); }
115 throw_if(left < 0 || right < 0,
"{}: values cannot be negative.", operation);
116 throw_if(left > numeric_limits<Index>::max() - right,
117 "{}: Index addition overflow.", operation);
123 throw_if(left < 0 || right < 0,
"{}: values cannot be negative.", operation);
124 if (left == 0 || right == 0)
return 0;
125 throw_if(left > numeric_limits<Index>::max() / right,
126 "{}: Index multiplication overflow.", operation);
130template<
typename Range,
typename Projection>
134 for (
const auto& value : values)
143 throw_if(alignment <= 0 || (alignment & (alignment - 1)) != 0,
144 "align_up: alignment must be a positive power of two.");
145 if (value == 0)
return 0;
152 "ceil_div: value must be non-negative and divisor must be positive.");
153 return value / divisor + Index(value % divisor != 0);
161 "get_aligned_bytes"));
166 return reinterpret_cast<uintptr_t
>(ptr) %
ALIGN_BYTES == 0;
180 throw_if(value < 0,
"Shape::filled: dimensions cannot be negative.");
184 fill_n(shape.dims, rank, value);
192 "Shape: initializer rank {} exceeds MaxRank={}.",
194 throw_if(ranges::any_of(list, [](Index value) {
return value < 0; }),
195 "Shape: dimensions cannot be negative.");
196 copy_n(list.begin(), rank, dims);
199 template<
typename It>
200 Shape(It first, It last) : rank(static_cast<size_t>(distance(first, last)))
203 "Shape: iterator-pair rank {} exceeds MaxRank={}.",
205 throw_if(any_of(first, last, [](Index value) {
return value < 0; }),
206 "Shape: dimensions cannot be negative.");
207 copy_n(first, rank, dims);
212 const Index*
begin() const noexcept {
return dims; }
213 const Index*
end() const noexcept {
return dims + rank; }
214 Index
operator[](
size_t i)
const noexcept {
return dims[i]; }
215 Index
back()
const {
throw_if(rank == 0,
"Shape::back() on empty");
return dims[rank - 1]; }
217 bool empty() const noexcept {
return rank == 0; }
219 Index
dim_or_zero(
size_t i)
const noexcept {
return i < rank ? dims[i] : Index(0); }
224 if (rank == 0)
return 0;
226 Index element_count = 1;
227 for (
const Index dimension : *
this)
230 return element_count;
238 "Shape::set_dimension: index {} is out of range for rank {}.",
240 throw_if(value < 0,
"Shape::set_dimension: dimensions cannot be negative.");
247 throw_if(value < 0,
"Shape::push_back: dimensions cannot be negative.");
248 dims[rank++] = value;
254 for (
size_t i = 0; i < shape.
get_rank(); ++i) os << (i ?
", " :
" ") << shape.dims[i];
261 return rank == other.get_rank() && equal(
begin(),
end(), other.begin());
267 "Shape::append: combined rank exceeds MaxRank={}.",
MaxRank);
268 throw_if(any_of(other.
begin(), other.
end(), [](Index value) { return value < 0; }),
269 "Shape::append: dimensions cannot be negative.");
270 copy_n(other.dims, other.
get_rank(), dims + rank);
292 "get_aligned_size(TensorSpec list)");
299 "get_aligned_size(TensorSpec groups)");
308 "get_aligned_bytes(TensorSpec list)");
315 "get_aligned_bytes(TensorSpec groups)");
322 "get_aligned_bytes(Shape list)");
328 [dtype](
const auto& spec) {
return get_aligned_bytes(spec.shape.size(), dtype); },
329 "get_aligned_bytes(TensorSpec list, dtype)");
336 "get_aligned_bytes(TensorSpec groups, dtype)");
343 validate_device(initial_device,
"Buffer");
351 if (
this == &other)
return *
this;
354 pointer = other.pointer;
355 allocated_bytes = other.allocated_bytes;
356 allocation_device = other.allocation_device;
357 owns_allocation = other.owns_allocation;
359 other.pointer =
nullptr;
360 other.allocated_bytes = 0;
362 other.owns_allocation =
true;
372 validate_state(
"Buffer::as");
373 return static_cast<T*
>(pointer);
379 validate_state(
"Buffer::as");
380 return static_cast<const T*
>(pointer);
383 void*
data() const noexcept {
return pointer; }
384 Index
byte_size() const noexcept {
return allocated_bytes; }
387 Index
size_in_floats() const noexcept {
return allocated_bytes / Index(
sizeof(
float)); }
388 bool empty() const noexcept {
return allocated_bytes == 0; }
392 validate_state(
"Buffer::as_vector");
394 "Buffer::as_vector requires host storage.");
395 throw_if(allocated_bytes % Index(
sizeof(
float)) != 0,
396 "Buffer::as_vector requires a whole number of floats.");
402 validate_state(
"Buffer::as_vector");
404 "Buffer::as_vector requires host storage.");
405 throw_if(allocated_bytes % Index(
sizeof(
float)) != 0,
406 "Buffer::as_vector requires a whole number of floats.");
412 validate_state(
"Buffer::resize_bytes");
413 validate_size_and_device(byte_count, new_device,
"Buffer::resize_bytes");
415 && byte_count == allocated_bytes
416 && allocation_device == new_device)
return;
418 const bool changes_cuda_allocation =
422 "CUDA buffer resize from {} to {} bytes while CUDA allocation growth is forbidden "
423 "(warmup incomplete before CUDA graph capture).",
427 Buffer replacement(new_device);
431 replacement.allocated_bytes = byte_count;
439 validate_state(
"Buffer::set_view");
440 validate_size_and_device(byte_count, view_device,
"Buffer::set_view");
441 throw_if((external_data ==
nullptr) != (byte_count == 0),
442 "Buffer::set_view requires null data exactly when the view is empty.");
443 throw_if(owns_allocation && pointer && external_data == pointer,
444 "Buffer::set_view cannot alias the buffer's owned allocation.");
446 Buffer replacement(view_device);
447 replacement.pointer = external_data;
448 replacement.allocated_bytes = byte_count;
449 replacement.owns_allocation =
false;
455 validate_state(
"Buffer::grow_to");
456 throw_if(minimum_bytes < 0,
"Buffer::grow_to size cannot be negative.");
457 if (minimum_bytes > allocated_bytes)
471 validate_state(
"Buffer::setZero");
477 validate_state(
"Buffer::migrate_to");
478 validate_device(target_device,
"Buffer::migrate_to");
479 if (allocation_device == target_device)
return;
481 Buffer target_buffer(target_device);
483 return swap(target_buffer);
485 target_buffer.
resize_bytes(allocated_bytes, target_device);
487 allocation_device, target_device, stream);
495 std::swap(pointer, other.pointer);
496 std::swap(allocated_bytes, other.allocated_bytes);
497 std::swap(allocation_device, other.allocation_device);
498 std::swap(owns_allocation, other.owns_allocation);
504 string_view operation)
509 static void validate_size_and_device(Index byte_count,
511 string_view operation)
513 throw_if(byte_count < 0,
"{} size cannot be negative.", operation);
514 validate_device(device, operation);
517 void validate_state(string_view operation)
const
519 validate_size_and_device(allocated_bytes, allocation_device, operation);
520 throw_if((pointer ==
nullptr) != (allocated_bytes == 0),
521 "{} found inconsistent data and byte count.", operation);
526 if (pointer && owns_allocation)
530 owns_allocation =
true;
533 void* pointer =
nullptr;
534 Index allocated_bytes = 0;
536 bool owns_allocation =
true;
542 const Shape& new_shape = {},
554 Index
get_rank() const noexcept {
return Index(shape.get_rank()); }
556 Index
size()
const {
return shape.size(); }
561 "TensorView::byte_size");
564 Index
flat_columns() const noexcept {
return shape.get_rank() == 0 ? 0 : shape[shape.get_rank() - 1]; }
568 return columns == 0 ? 0 : shape.size() / columns;
571 bool empty() const noexcept {
return shape.empty(); }
578 T*
as() const noexcept
581 return reinterpret_cast<T*
>(data);
586 return reinterpret_cast<float*
>(data);
599 const Index current_size =
size();
601 "TensorView::reshape cannot change the element count from {} to {}.",
602 current_size, new_shape.
size());
603 return TensorView(data, new_shape, type, device);
608 const Index current_size =
size();
610 "TensorView::reshape_prefix cannot grow the element count from {} to {}.",
611 current_size, new_shape.
size());
612 return TensorView(data, new_shape, type, device);
617 require_host_fp32_data(
"TensorView::as_matrix");
618 throw_if(shape.get_rank() < 2,
"TensorView::as_matrix requires rank >= 2.");
620 const Index row_count = shape[0];
621 const Index column_count = row_count == 0 ? 0 : shape.size() / row_count;
622 return MatrixMap(
reinterpret_cast<float*
>(data), row_count, column_count);
627 require_host_fp32_data(
"TensorView::as_matrix(matrix_index)");
629 "TensorView::as_matrix(matrix_index) requires rank >= 2.");
631 const Index row_count = shape[shape.get_rank() - 2];
632 const Index column_count = shape[shape.get_rank() - 1];
633 const Index matrix_element_count = row_count * column_count;
634 const Index matrix_count = matrix_element_count == 0
636 : shape.size() / matrix_element_count;
638 throw_if(matrix_index < 0 || matrix_index >= matrix_count,
639 "TensorView::as_matrix(matrix_index): matrix index {} out of range [0, {}).",
640 matrix_index, matrix_count);
642 return MatrixMap(
reinterpret_cast<float*
>(data) + matrix_index * matrix_element_count,
649 require_host_fp32_data(
"TensorView::as_flat_matrix");
650 throw_if(shape.get_rank() < 1,
"TensorView::as_flat_matrix requires rank >= 1.");
657 require_host_fp32_data(
"TensorView::as_vector");
658 return VectorMap(
reinterpret_cast<float*
>(data), shape.size());
664 require_host_fp32_data(
"TensorView::as_tensor");
666 "TensorView::as_tensor requires rank {}, got {}.", Rank, shape.get_rank());
668 Eigen::array<Index, Rank> dims;
669 copy_n(shape.begin(), Rank, dims.begin());
676 require_host_fp32_data(
"TensorView::as_tensor(batch_index)");
677 throw_if(shape.get_rank() != Rank + 1,
678 "TensorView::as_tensor(batch_index) requires rank {}, got {}.",
679 Rank + 1, shape.get_rank());
680 throw_if(batch_index < 0 || batch_index >= shape[0],
681 "TensorView::as_tensor(batch_index): batch index {} out of range [0, {}).",
682 batch_index, shape[0]);
684 Eigen::array<Index, Rank> dims;
685 for (
int i = 0; i < Rank; ++i) dims[i] = shape[i + 1];
686 const Index slice_element_count = shape.size() / shape[0];
688 + batch_index * slice_element_count,
699 void require_host_fp32(string_view accessor)
const
703 const char* dev_str = (device ==
Device::CUDA) ?
"CUDA" :
"CPU";
704 const char* typ_str = (type ==
Type::BF16) ?
"BF16" : (type ==
Type::
FP32 ?
"FP32" :
"other");
705 throw_if(
true,
"{} requires CPU FP32 storage. [device={} type={} rank={}]",
706 accessor, dev_str, typ_str,
int(shape.get_rank()));
710 void require_host_fp32_data(string_view accessor)
const
712 require_host_fp32(accessor);
713 throw_if(shape.
size() > 0 && !data,
"{} requires non-null data.", accessor);
716 void* data =
nullptr;
723 const vector<size_t>& slot_indices,
727 if (i >= slot_indices.size())
return fallback;
729 throw_if(slot_indices[i] >= views.size(),
730 "slot_or: slot index {} is out of range for {} views.",
731 slot_indices[i], views.size());
732 return views[slot_indices[i]];
735template<
typename T,
size_t N>
743 return ranges::adjacent_find(indices,
744 [](Index a, Index b) {
return b != a + 1; }) == indices.end();
756 const vector<Index>& indices)
766template<
typename... Vs>
770 ((h ^= hash<Vs>{}(values) + 0x9e3779b9 + (h << 6) + (h >> 2)), ...);
780inline const float one = 1.0f;
789 vector<uint16_t>& bf16_staging);
Index checked_index_sum(const Range &values, Projection projection, string_view operation)
Definition tensor_types.h:131
Index checked_index_multiply(Index left, Index right, string_view operation)
Definition tensor_types.h:121
Index checked_index_add(Index left, Index right, string_view operation)
Definition tensor_types.h:113
Definition energy_meter.h:7
void set_zero(void *, Index, Device)
void copy_async(void *, const void *, Index, CopyKind, DeviceStream=nullptr)
void * allocate(Device, Index)
bool cuda_allocation_growth_forbidden() noexcept
DeviceStream get_compute_stream()
void deallocate(Device, void *, Index) noexcept
void set_zero_async(void *, Index, DeviceStream=nullptr)
void synchronize(DeviceStream=nullptr)
Definition configuration.h:10
ColumnContiguity classify_column_contiguity(const vector< Index > &indices)
Definition tensor_types.h:749
bool is_aligned(const void *ptr)
Definition tensor_types.h:164
cudaDataType_t DeviceDataType
Definition opennn_types.h:168
size_t hash_combine(const Vs &... values)
Definition tensor_types.h:767
const float one
Definition tensor_types.h:780
float to_type(Index value)
Definition tensor_types.h:108
DeviceDataType to_cuda(Type type)
Definition tensor_types.h:89
Device
Definition configuration.h:12
@ Auto
Definition configuration.h:12
@ CPU
Definition configuration.h:12
@ CUDA
Definition configuration.h:12
Index get_aligned_bytes(Index n_bytes)
Definition tensor_types.h:157
Eigen::array< T, N > array
Definition tensor_types.h:736
void copy_device_to_host_float(const void *, Type, Index, float *, DeviceStream stream)
Index ceil_div(Index value, Index divisor)
Definition tensor_types.h:149
DnnDataType to_cudnn(Type type)
Definition tensor_types.h:84
Shape string_to_shape(const string &, const string &=" ")
constexpr BlasComputeType CUBLAS_COMPUTE_DTYPE
Definition tensor_types.h:169
const float zero
Definition tensor_types.h:781
bool is_contiguous(const vector< Index > &indices)
Definition tensor_types.h:741
Index get_aligned_size(Index size)
Definition tensor_types.h:156
cudnnDataType_t DnnDataType
Definition opennn_types.h:143
Type
Definition configuration.h:13
@ Auto
Definition configuration.h:13
@ FP32
Definition configuration.h:13
@ INT8
Definition configuration.h:13
@ BF16
Definition configuration.h:13
int to_int(Index value)
Definition tensor_types.h:102
auto with_type_info(Type type, const char *caller, F &&f)
Definition tensor_types.h:71
cublasComputeType_t BlasComputeType
Definition opennn_types.h:159
void fill_tensor_data(const MatrixR &, const vector< Index > &, const vector< Index > &, span< float >, ColumnContiguity=ColumnContiguity::Unknown)
Index type_bytes(Type type)
Definition tensor_types.h:94
void visit_type(Type t, F &&f)
Definition tensor_types.h:44
string shape_to_string(const Shape &, const string &=" ")
TensorView & slot_or(vector< TensorView > &views, const vector< size_t > &slot_indices, size_t i, TensorView &fallback)
Definition tensor_types.h:722
bool resolve_column_contiguity(ColumnContiguity column_contiguity, const vector< Index > &indices)
Definition tensor_types.h:755
cudaStream_t DeviceStream
Definition opennn_types.h:135
static constexpr Index ALIGN_BYTES
Definition tensor_types.h:99
void visit_type_pair(Type t_in, Type t_out, F &&f)
Definition tensor_types.h:59
Index align_up(Index value, Index alignment)
Definition tensor_types.h:141
__nv_bfloat16 bfloat16
Definition opennn_types.h:171
ColumnContiguity
Definition tensor_types.h:747
@ Contiguous
Definition tensor_types.h:747
@ NonContiguous
Definition tensor_types.h:747
@ Unknown
Definition tensor_types.h:747
static constexpr Index ALIGN_ELEMENTS
Definition tensor_types.h:100
float type
Definition opennn_types.h:197
Eigen::TensorMap< Eigen::Tensor< float, Rank, Layout|Eigen::AlignedMax >, Eigen::AlignedMax > TensorMapR
Definition opennn_types.h:362
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Layout > MatrixR
Definition opennn_types.h:331
Eigen::Map< const VectorR, Eigen::AlignedMax > ConstVectorMap
Definition opennn_types.h:340
Eigen::Map< VectorR, Eigen::AlignedMax > VectorMap
Definition opennn_types.h:339
#define EIGEN_MAX_ALIGN_BYTES
Definition opennn_types.h:16
#define throw_if(condition,...)
Definition opennn_types.h:243
Eigen::Map< MatrixR, Eigen::AlignedMax > MatrixMap
Definition opennn_types.h:342
Buffer & operator=(Buffer &&other) noexcept
Definition tensor_types.h:349
Index byte_size() const noexcept
Definition tensor_types.h:384
void resize_bytes(Index byte_count, Device new_device)
Definition tensor_types.h:410
void swap(Buffer &other) noexcept
Definition tensor_types.h:493
bool owns_memory() const noexcept
Definition tensor_types.h:386
void * data() const noexcept
Definition tensor_types.h:383
bool empty() const noexcept
Definition tensor_types.h:388
Buffer(Device initial_device=Device::CPU)
Definition tensor_types.h:341
VectorMap as_vector() &
Definition tensor_types.h:390
Buffer(Buffer &&other) noexcept
Definition tensor_types.h:348
void setZero()
Definition tensor_types.h:469
void migrate_to(Device target_device, DeviceStream stream=nullptr)
Definition tensor_types.h:475
void set_view(void *external_data, Index byte_count, Device view_device)
Definition tensor_types.h:437
T * ensure(Index element_count)
Definition tensor_types.h:462
ConstVectorMap as_vector() const &
Definition tensor_types.h:400
Index size_in_floats() const noexcept
Definition tensor_types.h:387
Buffer & operator=(const Buffer &)=delete
void grow_to(Index minimum_bytes)
Definition tensor_types.h:453
~Buffer()
Definition tensor_types.h:367
Buffer(const Buffer &)=delete
Device get_device() const noexcept
Definition tensor_types.h:385
T * as()
Definition tensor_types.h:370
const T * as() const
Definition tensor_types.h:377
Definition device_backend.h:17
Definition tensor_types.h:172
void set_dimension(size_t index, Index value)
Definition tensor_types.h:235
const Index * begin() const noexcept
Definition tensor_types.h:212
friend ostream & operator<<(ostream &os, const Shape &shape)
Definition tensor_types.h:251
Index size() const
Definition tensor_types.h:221
Index dim_or_zero(size_t i) const noexcept
Definition tensor_types.h:219
static constexpr size_t MaxRank
Definition tensor_types.h:173
size_t get_rank() const noexcept
Definition tensor_types.h:210
bool empty() const noexcept
Definition tensor_types.h:217
Shape(initializer_list< Index > list)
Definition tensor_types.h:189
Shape(It first, It last)
Definition tensor_types.h:200
const Index * end() const noexcept
Definition tensor_types.h:213
bool operator==(const Shape &other) const noexcept
Definition tensor_types.h:259
void push_back(Index value)
Definition tensor_types.h:244
void clear() noexcept
Definition tensor_types.h:233
static Shape filled(size_t rank, Index value)
Definition tensor_types.h:177
Shape & append(const Shape &other)
Definition tensor_types.h:264
Index back() const
Definition tensor_types.h:215
Index operator[](size_t i) const noexcept
Definition tensor_types.h:214
Definition tensor_types.h:281
Shape shape
Definition tensor_types.h:282
Type dtype
Definition tensor_types.h:283
bool operator==(const TensorSpec &) const noexcept=default
Definition tensor_types.h:540
MatrixMap as_matrix() const
Definition tensor_types.h:615
bool is_cuda() const noexcept
Definition tensor_types.h:572
bool empty() const noexcept
Definition tensor_types.h:571
MatrixMap as_matrix(Index matrix_index) const
Definition tensor_types.h:625
Index flat_rows() const noexcept
Definition tensor_types.h:565
void set_zero_async() const
Definition tensor_types.h:774
bool is_int8() const noexcept
Definition tensor_types.h:575
Type get_type() const noexcept
Definition tensor_types.h:552
const Shape & get_shape() const noexcept
Definition tensor_types.h:551
Device get_device() const noexcept
Definition tensor_types.h:553
MatrixMap as_flat_matrix() const
Definition tensor_types.h:647
TensorMapR< Rank > as_tensor(Index batch_index) const
Definition tensor_types.h:674
TensorView reshape_prefix(const Shape &new_shape) const
Definition tensor_types.h:606
void setZero() const
Definition tensor_types.h:693
Index get_rank() const noexcept
Definition tensor_types.h:554
VectorMap as_vector() const
Definition tensor_types.h:655
CudnnDescriptor< DnnTensorDescriptor > get_descriptor() const
float * as_float() const noexcept
Definition tensor_types.h:584
TensorView reshape(const Shape &new_shape) const
Definition tensor_types.h:597
Index byte_size() const
Definition tensor_types.h:558
TensorView(void *new_data=nullptr, const Shape &new_shape={}, Type new_type=Type::FP32, Device new_device=Device::CPU) noexcept
Definition tensor_types.h:541
T * as() const noexcept
Definition tensor_types.h:578
TensorMapR< Rank > as_tensor() const
Definition tensor_types.h:662
DeviceDataType cuda_dtype() const
Definition tensor_types.h:589
void dispatch(F &&fn) const
Definition tensor_types.h:592
void * get_data() const noexcept
Definition tensor_types.h:550
bool is_bf16() const noexcept
Definition tensor_types.h:574
bool is_fp32() const noexcept
Definition tensor_types.h:573
Index size() const
Definition tensor_types.h:556
Index flat_columns() const noexcept
Definition tensor_types.h:564
bfloat16 type
Definition tensor_types.h:27
static constexpr DnnDataType cudnn
Definition tensor_types.h:28
static constexpr Index bytes
Definition tensor_types.h:30
static constexpr DeviceDataType cuda
Definition tensor_types.h:29
static constexpr const char * name
Definition tensor_types.h:31
float type
Definition tensor_types.h:18
static constexpr Index bytes
Definition tensor_types.h:21
static constexpr const char * name
Definition tensor_types.h:22
static constexpr DeviceDataType cuda
Definition tensor_types.h:20
static constexpr DnnDataType cudnn
Definition tensor_types.h:19
static constexpr DnnDataType cudnn
Definition tensor_types.h:37
int8_t type
Definition tensor_types.h:36
static constexpr const char * name
Definition tensor_types.h:40
static constexpr Index bytes
Definition tensor_types.h:39
static constexpr DeviceDataType cuda
Definition tensor_types.h:38
Definition tensor_types.h:14