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,67 @@ 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 Tensor& input,
363
+ TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) {
364
+ const std::vector<int32_t > sizes (
365
+ input.sizes ().begin (), input.sizes ().end ());
366
+
367
+ std::vector<uint8_t > channels_last_dim_order =
368
+ internal::channels_last_dim_order (sizes.size ());
369
+ std::vector<exec_aten::StridesType> channels_last_strides =
370
+ internal::strides_from_dim_order (sizes, channels_last_dim_order);
371
+
372
+ for (int32_t i = 0 ; i < input.dim (); i++) {
373
+ ET_CHECK_MSG (
374
+ input.strides ()[i] == channels_last_strides[i],
375
+ " Input tensor is not contiguous" );
376
+ }
377
+
378
+ int32_t N = sizes[0 ];
379
+ int32_t C = sizes[1 ];
380
+ int32_t H = sizes[2 ];
381
+ int32_t W = sizes[3 ];
382
+
383
+ std::vector<ctype> contiguous_data (
384
+ input.data_ptr <ctype>(), input.data_ptr <ctype>() + input.numel ());
385
+ std::vector<ctype> channels_last_data (
386
+ N * C * H * W); // Create a new blob with the same total size to contain
387
+ // channels_last data
388
+ for (int32_t n = 0 ; n < N; ++n) {
389
+ for (int32_t c = 0 ; c < C; ++c) {
390
+ for (int32_t h = 0 ; h < H; ++h) {
391
+ for (int32_t w = 0 ; w < W; ++w) {
392
+ // Calculate the index in the original blob
393
+ int32_t old_index = ((n * C + c) * H + h) * W + w;
394
+ // Calculate the index in the new blob
395
+ int32_t new_index = ((n * H + h) * W + w) * C + c;
396
+ // Copy the data
397
+ channels_last_data[new_index] = contiguous_data[old_index];
398
+ }
399
+ }
400
+ }
401
+ }
402
+
403
+ return make_with_dimorder (
404
+ sizes,
405
+ channels_last_data,
406
+ internal::channels_last_dim_order (sizes.size ()),
407
+ dynamism);
408
+ }
409
+
347
410
/* *
348
411
* Returns a new Tensor with the specified shape, containing contiguous
349
412
* data will all elements set to `value`.
@@ -459,14 +522,13 @@ class TensorFactory {
459
522
*/
460
523
at::Tensor empty_strided (
461
524
const std::vector<int32_t >& sizes,
462
- const std::vector<int32_t >& strides,
525
+ const std::vector<exec_aten::StridesType >& strides,
463
526
__ET_UNUSED TensorShapeDynamism dynamism =
464
527
TensorShapeDynamism::DYNAMIC_UNBOUND) {
465
528
auto sizes64 = vec_32_to_64 (sizes);
466
- auto strides64 = vec_32_to_64 (strides);
467
529
return at::empty_strided (
468
530
sizes64,
469
- strides64 ,
531
+ strides ,
470
532
DTYPE,
471
533
/* layout_opt=*/ at::Layout::Strided,
472
534
/* device_opt=*/ at::Device (at::DeviceType::CPU),
@@ -665,7 +727,7 @@ class TensorFactory {
665
727
torch::executor::Tensor make (
666
728
const std::vector<int32_t >& sizes,
667
729
const std::vector<ctype>& data,
668
- const std::vector<int32_t > strides = {},
730
+ const std::vector<exec_aten::StridesType > strides = {},
669
731
TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) {
670
732
std::vector<int32_t > default_strides;
671
733
// Generate strides from the tensor dimensions, assuming contiguous data if
@@ -745,7 +807,7 @@ class TensorFactory {
745
807
746
808
/* *
747
809
* Returns a new Tensor with the specified shape and data in channels last
748
- * memory layout .
810
+ * memory format .
749
811
*
750
812
* @param[in] sizes The sizes of the dimensions of the Tensor.
751
813
* @param[in] data The data that the Tensor should be initialized with. The
@@ -763,6 +825,60 @@ class TensorFactory {
763
825
sizes, data, internal::channels_last_dim_order (sizes.size ()), dynamism);
764
826
}
765
827
828
+ /* *
829
+ * Given data in contiguous memory format, returns a new Tensor with the
830
+ * specified shape and the same data but in channels last memory format.
831
+ *
832
+ * @param[in] sizes The sizes of the dimensions of the Tensor.
833
+ * @param[in] data The data in contiguous memory format that the Tensor should
834
+ * be initialized with. The size of this vector must be equal to the product
835
+ * of the elements of `sizes`.
836
+ *
837
+ * @return A new Tensor with the specified shape and data in channls last
838
+ * memory format.
839
+ */
840
+ torch::executor::Tensor channels_last_like (
841
+ const Tensor& input,
842
+ TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) {
843
+ const std::vector<int32_t > sizes (
844
+ input.sizes ().begin (), input.sizes ().end ());
845
+
846
+ ET_CHECK_MSG (sizes.size () == 4 , " Only 4D tensors can be channels last" );
847
+ ET_CHECK_MSG (
848
+ is_contiguous_dim_order (input.dim_order ().data (), input.dim ()) == true ,
849
+ " Input tensor is not contiguous" );
850
+ int32_t N = sizes[0 ];
851
+ int32_t C = sizes[1 ];
852
+ int32_t H = sizes[2 ];
853
+ int32_t W = sizes[3 ];
854
+
855
+ std::vector<ctype> contiguous_data (
856
+ input.data_ptr <ctype>(), input.data_ptr <ctype>() + input.numel ());
857
+ std::vector<ctype> channels_last_data (
858
+ N * C * H * W); // Create a new blob with the same total size to contain
859
+ // channels_last data
860
+ for (int32_t n = 0 ; n < N; ++n) {
861
+ for (int32_t c = 0 ; c < C; ++c) {
862
+ for (int32_t h = 0 ; h < H; ++h) {
863
+ for (int32_t w = 0 ; w < W; ++w) {
864
+ // Calculate the index in the original blob
865
+ int32_t old_index = ((n * C + c) * H + h) * W + w;
866
+ // Calculate the index in the new blob
867
+ int32_t new_index = ((n * H + h) * W + w) * C + c;
868
+ // Copy the data
869
+ channels_last_data[new_index] = contiguous_data[old_index];
870
+ }
871
+ }
872
+ }
873
+ }
874
+
875
+ return make_with_dimorder (
876
+ sizes,
877
+ channels_last_data,
878
+ internal::channels_last_dim_order (sizes.size ()),
879
+ dynamism);
880
+ }
881
+
766
882
/* *
767
883
* Returns a new Tensor with the specified shape, containing contiguous data
768
884
* will all elements set to `value`.
@@ -798,7 +914,20 @@ class TensorFactory {
798
914
799
915
/* *
800
916
* Returns a new Tensor with the specified shape, containing contiguous data
801
- * with all `0` elements.
917
+ * in channels last memory format with all `0` elements.
918
+ *
919
+ * @param[in] sizes The sizes of the dimensions of the Tensor.
920
+ * @return A new Tensor with the specified shape.
921
+ */
922
+ torch::executor::Tensor zeros_channels_last (
923
+ const std::vector<int32_t >& sizes,
924
+ TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) {
925
+ return full_channels_last (sizes, 0 , dynamism);
926
+ }
927
+
928
+ /* *
929
+ * Returns a new Tensor with the specified shape, containing contiguous data
930
+ * in contiguous memory format with all `0` elements.
802
931
*
803
932
* @param[in] sizes The sizes of the dimensions of the Tensor.
804
933
* @return A new Tensor with the specified shape.
@@ -877,7 +1006,7 @@ class TensorFactory {
877
1006
std::vector<int32_t > sizes_;
878
1007
std::vector<ctype> data_;
879
1008
std::vector<uint8_t > dim_order_;
880
- std::vector<int32_t > strides_;
1009
+ std::vector<exec_aten::StridesType > strides_;
881
1010
TensorImpl impl_;
882
1011
};
883
1012
0 commit comments