3
3
#pragma once
4
4
5
5
#include < algorithm>
6
+ #include < cstdint>
6
7
7
8
#include < executorch/runtime/core/exec_aten/exec_aten.h>
9
+ #include < executorch/runtime/core/exec_aten/util/dim_order_util.h>
8
10
#include < executorch/runtime/core/exec_aten/util/scalar_type_util.h>
9
11
#include < executorch/runtime/core/tensor_shape_dynamism.h>
10
12
#include < executorch/runtime/platform/assert.h>
@@ -54,7 +56,7 @@ inline size_t sizes_to_numel(const std::vector<int32_t>& sizes) {
54
56
55
57
inline bool check_strides (
56
58
const std::vector<int32_t > sizes,
57
- const std::vector<int32_t > strides) {
59
+ const std::vector<exec_aten::StridesType > strides) {
58
60
if (sizes.size () != strides.size ()) {
59
61
// The length of stride vector shall equal to size vector.
60
62
return false ;
@@ -147,14 +149,14 @@ inline bool check_dim_order(
147
149
return true ;
148
150
}
149
151
150
- inline std::vector<int32_t > strides_from_dim_order (
152
+ inline std::vector<exec_aten::StridesType > strides_from_dim_order (
151
153
const std::vector<int32_t >& sizes,
152
154
const std::vector<uint8_t >& dim_order) {
153
155
bool legal = check_dim_order (sizes, dim_order);
154
156
ET_CHECK_MSG (legal, " The input dim_order variable is illegal." );
155
157
156
158
size_t ndim = sizes.size ();
157
- std::vector<int32_t > strides (ndim);
159
+ std::vector<exec_aten::StridesType > strides (ndim);
158
160
strides[dim_order[ndim - 1 ]] = 1 ;
159
161
for (int i = ndim - 2 ; i >= 0 ; --i) {
160
162
uint8_t cur_dim = dim_order[i];
@@ -258,7 +260,7 @@ class TensorFactory {
258
260
at::Tensor make (
259
261
const std::vector<int32_t >& sizes,
260
262
const std::vector<ctype>& data,
261
- const std::vector<int32_t > strides = {},
263
+ const std::vector<exec_aten::StridesType > strides = {},
262
264
ET_UNUSED TensorShapeDynamism dynamism =
263
265
TensorShapeDynamism::DYNAMIC_UNBOUND) {
264
266
auto expected_numel = internal::sizes_to_numel (sizes);
@@ -344,6 +346,72 @@ class TensorFactory {
344
346
sizes, data, internal::channels_last_dim_order (sizes.size ()), dynamism);
345
347
}
346
348
349
+ /* *
350
+ * Given data in contiguous memory format, returns a new Tensor with the
351
+ * specified shape and the same data but in channels last memory format.
352
+ *
353
+ * @param[in] sizes The sizes of the dimensions of the Tensor.
354
+ * @param[in] data The data in contiguous memory format that the Tensor should
355
+ * be initialized with. The size of this vector must be equal to the product
356
+ * of the elements of `sizes`.
357
+ *
358
+ * @return A new Tensor with the specified shape and data in channls last
359
+ * memory format.
360
+ */
361
+ at::Tensor channels_last_like (
362
+ const at::Tensor& input,
363
+ TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) {
364
+ ET_CHECK_MSG (
365
+ input.sizes ().size () == 4 , " Only 4D tensors can be channels last" );
366
+
367
+ const std::vector<int32_t > sizes (
368
+ input.sizes ().begin (), input.sizes ().end ());
369
+
370
+ std::vector<uint8_t > contiguous_dim_order (sizes.size ());
371
+ for (uint8_t i = 0 ; i < sizes.size (); i++) {
372
+ contiguous_dim_order[i] = i;
373
+ }
374
+ std::vector<exec_aten::StridesType> contiguous_strides =
375
+ internal::strides_from_dim_order (sizes, contiguous_dim_order);
376
+
377
+ for (int32_t i = 0 ; i < input.dim (); i++) {
378
+ ET_CHECK_MSG (
379
+ input.strides ()[i] == contiguous_strides[i],
380
+ " Input tensor is not contiguous" );
381
+ }
382
+
383
+ int32_t N = sizes[0 ];
384
+ int32_t C = sizes[1 ];
385
+ int32_t H = sizes[2 ];
386
+ int32_t W = sizes[3 ];
387
+
388
+ std::vector<ctype> contiguous_data (
389
+ input.data_ptr <ctype>(), input.data_ptr <ctype>() + input.numel ());
390
+ std::vector<ctype> channels_last_data (
391
+ N * C * H * W); // Create a new blob with the same total size to contain
392
+ // channels_last data
393
+ for (int32_t n = 0 ; n < N; ++n) {
394
+ for (int32_t c = 0 ; c < C; ++c) {
395
+ for (int32_t h = 0 ; h < H; ++h) {
396
+ for (int32_t w = 0 ; w < W; ++w) {
397
+ // Calculate the index in the original blob
398
+ int32_t old_index = ((n * C + c) * H + h) * W + w;
399
+ // Calculate the index in the new blob
400
+ int32_t new_index = ((n * H + h) * W + w) * C + c;
401
+ // Copy the data
402
+ channels_last_data[new_index] = contiguous_data[old_index];
403
+ }
404
+ }
405
+ }
406
+ }
407
+
408
+ return make_with_dimorder (
409
+ sizes,
410
+ channels_last_data,
411
+ internal::channels_last_dim_order (sizes.size ()),
412
+ dynamism);
413
+ }
414
+
347
415
/* *
348
416
* Returns a new Tensor with the specified shape, containing contiguous
349
417
* data will all elements set to `value`.
@@ -459,14 +527,13 @@ class TensorFactory {
459
527
*/
460
528
at::Tensor empty_strided (
461
529
const std::vector<int32_t >& sizes,
462
- const std::vector<int32_t >& strides,
530
+ const std::vector<exec_aten::StridesType >& strides,
463
531
ET_UNUSED TensorShapeDynamism dynamism =
464
532
TensorShapeDynamism::DYNAMIC_UNBOUND) {
465
533
auto sizes64 = vec_32_to_64 (sizes);
466
- auto strides64 = vec_32_to_64 (strides);
467
534
return at::empty_strided (
468
535
sizes64,
469
- strides64 ,
536
+ strides ,
470
537
DTYPE,
471
538
/* layout_opt=*/ at::Layout::Strided,
472
539
/* device_opt=*/ at::Device (at::DeviceType::CPU),
@@ -666,7 +733,7 @@ class TensorFactory {
666
733
torch::executor::Tensor make (
667
734
const std::vector<int32_t >& sizes,
668
735
const std::vector<ctype>& data,
669
- const std::vector<int32_t > strides = {},
736
+ const std::vector<exec_aten::StridesType > strides = {},
670
737
TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) {
671
738
std::vector<int32_t > default_strides;
672
739
// Generate strides from the tensor dimensions, assuming contiguous data if
@@ -746,7 +813,7 @@ class TensorFactory {
746
813
747
814
/* *
748
815
* Returns a new Tensor with the specified shape and data in channels last
749
- * memory layout .
816
+ * memory format .
750
817
*
751
818
* @param[in] sizes The sizes of the dimensions of the Tensor.
752
819
* @param[in] data The data that the Tensor should be initialized with. The
@@ -764,6 +831,60 @@ class TensorFactory {
764
831
sizes, data, internal::channels_last_dim_order (sizes.size ()), dynamism);
765
832
}
766
833
834
+ /* *
835
+ * Given data in contiguous memory format, returns a new Tensor with the
836
+ * specified shape and the same data but in channels last memory format.
837
+ *
838
+ * @param[in] sizes The sizes of the dimensions of the Tensor.
839
+ * @param[in] data The data in contiguous memory format that the Tensor should
840
+ * be initialized with. The size of this vector must be equal to the product
841
+ * of the elements of `sizes`.
842
+ *
843
+ * @return A new Tensor with the specified shape and data in channls last
844
+ * memory format.
845
+ */
846
+ torch::executor::Tensor channels_last_like (
847
+ const torch::executor::Tensor& input,
848
+ TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) {
849
+ const std::vector<int32_t > sizes (
850
+ input.sizes ().begin (), input.sizes ().end ());
851
+
852
+ ET_CHECK_MSG (sizes.size () == 4 , " Only 4D tensors can be channels last" );
853
+ ET_CHECK_MSG (
854
+ is_contiguous_dim_order (input.dim_order ().data (), input.dim ()) == true ,
855
+ " Input tensor is not contiguous" );
856
+ int32_t N = sizes[0 ];
857
+ int32_t C = sizes[1 ];
858
+ int32_t H = sizes[2 ];
859
+ int32_t W = sizes[3 ];
860
+
861
+ std::vector<ctype> contiguous_data (
862
+ input.data_ptr <ctype>(), input.data_ptr <ctype>() + input.numel ());
863
+ std::vector<ctype> channels_last_data (
864
+ N * C * H * W); // Create a new blob with the same total size to contain
865
+ // channels_last data
866
+ for (int32_t n = 0 ; n < N; ++n) {
867
+ for (int32_t c = 0 ; c < C; ++c) {
868
+ for (int32_t h = 0 ; h < H; ++h) {
869
+ for (int32_t w = 0 ; w < W; ++w) {
870
+ // Calculate the index in the original blob
871
+ int32_t old_index = ((n * C + c) * H + h) * W + w;
872
+ // Calculate the index in the new blob
873
+ int32_t new_index = ((n * H + h) * W + w) * C + c;
874
+ // Copy the data
875
+ channels_last_data[new_index] = contiguous_data[old_index];
876
+ }
877
+ }
878
+ }
879
+ }
880
+
881
+ return make_with_dimorder (
882
+ sizes,
883
+ channels_last_data,
884
+ internal::channels_last_dim_order (sizes.size ()),
885
+ dynamism);
886
+ }
887
+
767
888
/* *
768
889
* Returns a new Tensor with the specified shape, containing contiguous data
769
890
* will all elements set to `value`.
@@ -799,7 +920,20 @@ class TensorFactory {
799
920
800
921
/* *
801
922
* Returns a new Tensor with the specified shape, containing contiguous data
802
- * with all `0` elements.
923
+ * in channels last memory format with all `0` elements.
924
+ *
925
+ * @param[in] sizes The sizes of the dimensions of the Tensor.
926
+ * @return A new Tensor with the specified shape.
927
+ */
928
+ torch::executor::Tensor zeros_channels_last (
929
+ const std::vector<int32_t >& sizes,
930
+ TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) {
931
+ return full_channels_last (sizes, 0 , dynamism);
932
+ }
933
+
934
+ /* *
935
+ * Returns a new Tensor with the specified shape, containing contiguous data
936
+ * in contiguous memory format with all `0` elements.
803
937
*
804
938
* @param[in] sizes The sizes of the dimensions of the Tensor.
805
939
* @return A new Tensor with the specified shape.
@@ -878,7 +1012,7 @@ class TensorFactory {
878
1012
std::vector<int32_t > sizes_;
879
1013
std::vector<ctype> data_;
880
1014
std::vector<uint8_t > dim_order_;
881
- std::vector<int32_t > strides_;
1015
+ std::vector<exec_aten::StridesType > strides_;
882
1016
torch::executor::TensorImpl impl_;
883
1017
};
884
1018
0 commit comments