[Transform] Add Transpose Mode
authorjijoong.moon <jijoong.moon@samsung.com>
Wed, 12 Sep 2018 07:42:56 +0000 (16:42 +0900)
committerMyungJoo Ham <myungjoo.ham@gmail.com>
Thu, 13 Sep 2018 04:33:53 +0000 (13:33 +0900)
We may need transpose operation such as tensor_A[I][J][K][L] to
trneosr_B[I][J][L][K].

In order to support this, transpose mode is added. It is working with
"mode=transpose, option=0:1:3:2" (Notice that the first dim is always
fixed).

**Self evaluation:**
1. Build test:  [X]Passed [ ]Failed [ ]Skipped
2. Run test:  [X]Passed [ ]Failed [ ]Skipped

Signed-off-by: jijoong.moon <jijoong.moon@samsung.com>
gst/tensor_transform/tensor_transform.c
gst/tensor_transform/tensor_transform.h

index 00506e0..ca3c230 100644 (file)
@@ -192,6 +192,7 @@ static const gchar *gst_tensor_transform_mode_string[] = {
   [GTT_DIMCHG] = "dimchg",
   [GTT_TYPECAST] = "typecast",
   [GTT_ARITHMETIC] = "arithmetic",
+  [GTT_TRANSPOSE] = "transpose",
   [GTT_END] = "error",
 };
 
@@ -283,6 +284,20 @@ gst_tensor_transform_set_option_data (GstTensor_Transform * filter)
       filter->loaded = TRUE;
     }
       break;
+    case GTT_TRANSPOSE:
+    {
+      int a, i;
+      gchar **strv = g_strsplit (filter->option, ":", 4);
+      for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
+        if (strv[i] != NULL)
+          a = g_ascii_strtoull (strv[i], NULL, 10);
+        else
+          a = 0;
+        filter->data_transpose.trans_order[i] = a;
+      }
+      filter->loaded = TRUE;
+    }
+      break;
     default:
       g_printerr ("Cannot identify mode\n");
       g_assert (0);
@@ -635,6 +650,89 @@ gst_tensor_transform_arithmetic (GstTensor_Transform * filter,
 
 
 /**
+ * Macro to run loop for various data types with transpose
+ */
+#define transposeloop(cl, ck, cj, ci, sl, sk, sj, si, typesize) do {        \
+    size_t i, j, k, l;                                  \
+    int inidx = 0, outidx=0;                            \
+    for(cl=0;cl<sl;cl++)                      \
+      for(ci=0;ci<si;ci++)                    \
+       for(cj=0;cj<sj;cj++)                  \
+         for(ck=0;ck<sk;ck++){               \
+           outidx=si*sj*sk*cl + sj*sk*ci + sk*cj+ck; \
+           inidx = SK*SJ*SI*l + SJ*SI*k + SI*j + i; \
+           const uint8_t *_in = inptr+inidx*typesize; \
+           uint8_t *_out = outptr + outidx *typesize; \
+           memcpy(_out, _in, typesize);\
+         }                                                      \
+  } while(0);
+
+/**
+ * @brief subrouting for tensor-tranform, "transpose" case.
+ * @param[in/out] filter "this" pointer
+ * @param[in] inptr input tensor
+ * @param[out] outptr output tensor
+ * @return Gst flow status
+ */
+static GstFlowReturn
+gst_tensor_transform_transpose (GstTensor_Transform * filter,
+    const uint8_t * inptr, uint8_t * outptr)
+{
+  int i, from, to;
+  gboolean checkdim = FALSE;
+  uint32_t *fromDim = filter->fromDim;
+  size_t type_size = tensor_element_size[filter->type];
+  size_t indexI, indexJ, SL, SI, SJ, SK;
+  for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
+    from = i;
+    to = filter->data_transpose.trans_order[i];
+    if (from != to) {
+      checkdim = TRUE;
+      break;
+    }
+  }
+
+  if (!checkdim) {
+    memcpy (outptr, inptr,
+        get_tensor_element_count (filter->fromDim) * type_size);
+    g_printerr
+        ("Calling tensor_transform with high memcpy overhead WITHOUT any effects!");
+    return GST_FLOW_OK;
+  }
+
+  indexI = filter->data_transpose.trans_order[1];
+  indexJ = filter->data_transpose.trans_order[2];
+  SL = fromDim[0], SI = fromDim[1], SJ = fromDim[2], SK = fromDim[3];
+
+  switch (indexI) {
+    case 1:
+      if (indexJ == 2) {
+        transposeloop (l, i, j, k, SL, SI, SJ, SK, type_size);
+      } else {
+        transposeloop (l, i, k, j, SL, SI, SK, SJ, type_size);
+      }
+      break;
+    case 2:
+      if (indexJ == 1) {
+        transposeloop (l, j, i, k, SL, SJ, SI, SK, type_size);
+      } else {
+        transposeloop (l, j, k, i, SL, SJ, SK, SI, type_size);
+      }
+      break;
+    case 3:
+      if (indexJ == 1) {
+        transposeloop (l, k, i, j, SL, SK, SI, SJ, type_size);
+      } else {
+        transposeloop (l, k, j, i, SL, SK, SJ, SI, type_size);
+      }
+      break;
+  }
+
+  return GST_FLOW_OK;
+}
+
+
+/**
  * @brief non-ip transform. required vmethod for BaseTransform class.
  * @param[in/out] trans "super" pointer
  * @param[in] inbuf The input gst buffer
@@ -666,6 +764,9 @@ gst_tensor_transform_transform (GstBaseTransform * trans,
     case GTT_ARITHMETIC:
       res = gst_tensor_transform_arithmetic (filter, inptr, outptr);
       break;
+    case GTT_TRANSPOSE:
+      res = gst_tensor_transform_transpose (filter, inptr, outptr);
+      break;
     default:
       res = GST_FLOW_NOT_SUPPORTED;
   }
@@ -854,6 +955,22 @@ gst_tensor_dimension_conversion (GstTensor_Transform * filter,
       ret = TRUE;
     }
       break;
+    case GTT_TRANSPOSE:
+    {
+      *destType = srcType;
+      int i;
+      if (direction == GST_PAD_SINK) {
+        for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
+          destDim[i] = srcDim[filter->data_transpose.trans_order[i]];
+        }
+      } else {
+        for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
+          destDim[filter->data_transpose.trans_order[i]] = srcDim[i];
+        }
+      }
+      ret = TRUE;
+    }
+      break;
     default:
       return FALSE;
   }
@@ -1006,6 +1123,7 @@ gst_tensor_transform_set_caps (GstBaseTransform * trans,
     filter->type = itype;
 
   switch (filter->mode) {
+    case GTT_TRANSPOSE:
     case GTT_ARITHMETIC:
     case GTT_DIMCHG:
       if (itype != otype || filter->type != itype) {
@@ -1041,6 +1159,7 @@ gst_tensor_transform_transform_size (GstBaseTransform * trans,
 {
   GstTensor_Transform *filter = GST_TENSOR_TRANSFORM_CAST (trans);
   switch (filter->mode) {
+    case GTT_TRANSPOSE:
     case GTT_ARITHMETIC:
     case GTT_DIMCHG:
       *othersize = size;        /* size of input = size of output if dimchg */
index 1e07175..5eaa07b 100644 (file)
@@ -71,6 +71,7 @@ typedef enum
   GTT_DIMCHG = 0,               /* Dimension Change. "dimchg" */
   GTT_TYPECAST = 1,             /* Type change. "typecast" */
   GTT_ARITHMETIC = 2,           /* Type change. "typecast" */
+  GTT_TRANSPOSE = 3,            /* Transpose. "transpose" */
 
   GTT_END,
 } tensor_transform_mode;
@@ -107,6 +108,13 @@ typedef struct _tensor_transform_arithmetic {
 } tensor_transform_arithmetic;
 
 /**
+ * @brief Internal data structure for transpose mode.
+ */
+typedef struct _tensor_transform_transpose {
+  uint8_t trans_order[NNS_TENSOR_RANK_LIMIT];
+} tensor_transform_transpose;
+
+/**
  * @brief Internal data structure for tensor_transform instances.
  */
 struct _GstTensor_Transform
@@ -120,6 +128,7 @@ struct _GstTensor_Transform
     tensor_transform_dimchg data_dimchg; /**< Parsed option value for "dimchg" mode */
     tensor_transform_typecast data_typecast; /**< Parsed option value for "typecast" mode. */
     tensor_transform_arithmetic data_arithmetic; /**< Parsed option value for "arithmetic" mode. */
+    tensor_transform_transpose data_transpose; /**< Parsed option value for "transpose" mode. */
   };
   gboolean loaded; /**< TRUE if mode & option are loaded */