Add Q16x8 Depthwise Conv Support (#2140)

Adds support for 16-bit activations + 8-bit weights for depthwise convolution in the reference kernel. Uses 64-bit bias to match TFLite. Also adds passthrough to the q16x8 reference kernel for Xtensa, CEVA, and ARC (CMSIS already has it's own implementation).

Tested:
depthwise_conv_test

BUG=2141
diff --git a/tensorflow/lite/micro/kernels/arc_mli/depthwise_conv.cc b/tensorflow/lite/micro/kernels/arc_mli/depthwise_conv.cc
index 1fa1d19..c2c9cd5 100644
--- a/tensorflow/lite/micro/kernels/arc_mli/depthwise_conv.cc
+++ b/tensorflow/lite/micro/kernels/arc_mli/depthwise_conv.cc
@@ -660,6 +660,30 @@
                                 bias, output);
       }
       break;
+    case kTfLiteInt16: {
+      switch (filter->type) {
+        case kTfLiteInt8: {
+          reference_integer_ops::DepthwiseConvPerChannel(
+              DepthwiseConvParamsQuantized(params, data),
+              data.per_channel_output_multiplier, data.per_channel_output_shift,
+              tflite::micro::GetTensorShape(input),
+              tflite::micro::GetTensorData<int16_t>(input),
+              tflite::micro::GetTensorShape(filter),
+              tflite::micro::GetTensorData<int8_t>(filter),
+              tflite::micro::GetTensorShape(bias),
+              tflite::micro::GetOptionalTensorData<int64_t>(bias),
+              tflite::micro::GetTensorShape(output),
+              tflite::micro::GetTensorData<int16_t>(output));
+          break;
+        }
+        default:
+          MicroPrintf("Filter type %s (%d) for input type %s not supported.",
+                      TfLiteTypeGetName(filter->type), filter->type,
+                      TfLiteTypeGetName(input->type));
+          return kTfLiteError;
+      }
+      break;
+    }
     default:
       MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type),
                   input->type);
diff --git a/tensorflow/lite/micro/kernels/ceva/depthwise_conv.cc b/tensorflow/lite/micro/kernels/ceva/depthwise_conv.cc
index 533014f..eed5d9e 100644
--- a/tensorflow/lite/micro/kernels/ceva/depthwise_conv.cc
+++ b/tensorflow/lite/micro/kernels/ceva/depthwise_conv.cc
@@ -224,6 +224,30 @@
       EvalQuantizedPerChannel(context, node, params, data, input, filter, bias,

                               output);

       break;

+    case kTfLiteInt16: {

+      switch (filter->type) {

+        case kTfLiteInt8: {

+          reference_integer_ops::DepthwiseConvPerChannel(

+              DepthwiseConvParamsQuantized(*params, data),

+              data.per_channel_output_multiplier, data.per_channel_output_shift,

+              tflite::micro::GetTensorShape(input),

+              tflite::micro::GetTensorData<int16_t>(input),

+              tflite::micro::GetTensorShape(filter),

+              tflite::micro::GetTensorData<int8_t>(filter),

+              tflite::micro::GetTensorShape(bias),

+              tflite::micro::GetOptionalTensorData<int64_t>(bias),

+              tflite::micro::GetTensorShape(output),

+              tflite::micro::GetTensorData<int16_t>(output));

+          break;

+        }

+        default:

+          MicroPrintf("Filter type %s (%d) for input type %s not supported.",

+                      TfLiteTypeGetName(filter->type), filter->type,

+                      TfLiteTypeGetName(input->type));

+          return kTfLiteError;

+      }

+      break;

+    }

     default:

       MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type),

                   input->type);

diff --git a/tensorflow/lite/micro/kernels/depthwise_conv.cc b/tensorflow/lite/micro/kernels/depthwise_conv.cc
index 9290c2d..398f8cd 100644
--- a/tensorflow/lite/micro/kernels/depthwise_conv.cc
+++ b/tensorflow/lite/micro/kernels/depthwise_conv.cc
@@ -101,8 +101,33 @@
           break;
         }
         default:
-          MicroPrintf("Filter type %s (%d) not supported.",
-                      TfLiteTypeGetName(filter->type), filter->type);
+          MicroPrintf("Filter type %s (%d) for input type %s not supported.",
+                      TfLiteTypeGetName(filter->type), filter->type,
+                      TfLiteTypeGetName(input->type));
+          return kTfLiteError;
+      }
+      break;
+    }
+    case kTfLiteInt16: {
+      switch (filter->type) {
+        case kTfLiteInt8: {
+          reference_integer_ops::DepthwiseConvPerChannel(
+              DepthwiseConvParamsQuantized(params, data),
+              data.per_channel_output_multiplier, data.per_channel_output_shift,
+              tflite::micro::GetTensorShape(input),
+              tflite::micro::GetTensorData<int16_t>(input),
+              tflite::micro::GetTensorShape(filter),
+              tflite::micro::GetTensorData<int8_t>(filter),
+              tflite::micro::GetTensorShape(bias),
+              tflite::micro::GetOptionalTensorData<int64_t>(bias),
+              tflite::micro::GetTensorShape(output),
+              tflite::micro::GetTensorData<int16_t>(output));
+          break;
+        }
+        default:
+          MicroPrintf("Filter type %s (%d) for input type %s not supported.",
+                      TfLiteTypeGetName(filter->type), filter->type,
+                      TfLiteTypeGetName(input->type));
           return kTfLiteError;
       }
       break;
diff --git a/tensorflow/lite/micro/kernels/depthwise_conv_common.cc b/tensorflow/lite/micro/kernels/depthwise_conv_common.cc
index 6d5f6c2..52804de 100644
--- a/tensorflow/lite/micro/kernels/depthwise_conv_common.cc
+++ b/tensorflow/lite/micro/kernels/depthwise_conv_common.cc
@@ -192,7 +192,8 @@
       context,
       input->type == filter->type ||
           (input->type == kTfLiteInt8 &&
-           (filter->type == kTfLiteInt4 || filter->type == kTfLiteInt8)),
+           (filter->type == kTfLiteInt4 || filter->type == kTfLiteInt8)) ||
+          (input->type == kTfLiteInt16 && filter->type == kTfLiteInt8),
       "Hybrid models are not supported on TFLite Micro.");
 
   if (filter->type == kTfLiteInt4) {
diff --git a/tensorflow/lite/micro/kernels/depthwise_conv_test.cc b/tensorflow/lite/micro/kernels/depthwise_conv_test.cc
index c3b916c..b50b40a 100644
--- a/tensorflow/lite/micro/kernels/depthwise_conv_test.cc
+++ b/tensorflow/lite/micro/kernels/depthwise_conv_test.cc
@@ -78,15 +78,15 @@
   return kTfLiteOk;
 }
 
+template <typename T, typename BiasT>
 void TestDepthwiseConvQuantizedPerChannel(
-    int* input_dims_data, const float* input_data, int8_t* input_quantized,
+    int* input_dims_data, const float* input_data, T* input_quantized,
     float input_scale, int input_zero_point, int* filter_dims_data,
     const float* filter_data, int8_t* filter_data_quantized,
-    int* bias_dims_data, const float* bias_data, int32_t* bias_data_quantized,
+    int* bias_dims_data, const float* bias_data, BiasT* bias_data_quantized,
     int* output_dims_data, const float* expected_output_data,
-    int8_t* expected_output_data_quantized, int8_t* output_data,
-    float output_scale, int output_zero_point,
-    TfLiteDepthwiseConvParams* conv_params,
+    T* expected_output_data_quantized, T* output_data, float output_scale,
+    int output_zero_point, TfLiteDepthwiseConvParams* conv_params,
     TfLiteType filter_packed_type = kTfLiteNoType) {
   TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
   TfLiteIntArray* filter_dims = IntArrayFromInts(filter_dims_data);
@@ -147,6 +147,42 @@
                                               1.0, tensors_size, tensors));
 }
 
+void TestDepthwiseConvQuantizedPerChannel(
+    int* input_dims_data, const float* input_data, int8_t* input_quantized,
+    float input_scale, int input_zero_point, int* filter_dims_data,
+    const float* filter_data, int8_t* filter_data_quantized,
+    int* bias_dims_data, const float* bias_data, int32_t* bias_data_quantized,
+    int* output_dims_data, const float* expected_output_data,
+    int8_t* expected_output_data_quantized, int8_t* output_data,
+    float output_scale, int output_zero_point,
+    TfLiteDepthwiseConvParams* conv_params,
+    TfLiteType filter_packed_type = kTfLiteNoType) {
+  return TestDepthwiseConvQuantizedPerChannel<int8_t, int32_t>(
+      input_dims_data, input_data, input_quantized, input_scale,
+      input_zero_point, filter_dims_data, filter_data, filter_data_quantized,
+      bias_dims_data, bias_data, bias_data_quantized, output_dims_data,
+      expected_output_data, expected_output_data_quantized, output_data,
+      output_scale, output_zero_point, conv_params, filter_packed_type);
+}
+
+void TestDepthwiseConvQuantizedPerChannel(
+    int* input_dims_data, const float* input_data, int16_t* input_quantized,
+    float input_scale, int input_zero_point, int* filter_dims_data,
+    const float* filter_data, int8_t* filter_data_quantized,
+    int* bias_dims_data, const float* bias_data, int64_t* bias_data_quantized,
+    int* output_dims_data, const float* expected_output_data,
+    int16_t* expected_output_data_quantized, int16_t* output_data,
+    float output_scale, int output_zero_point,
+    TfLiteDepthwiseConvParams* conv_params,
+    TfLiteType filter_packed_type = kTfLiteNoType) {
+  return TestDepthwiseConvQuantizedPerChannel<int16_t, int64_t>(
+      input_dims_data, input_data, input_quantized, input_scale,
+      input_zero_point, filter_dims_data, filter_data, filter_data_quantized,
+      bias_dims_data, bias_data, bias_data_quantized, output_dims_data,
+      expected_output_data, expected_output_data_quantized, output_data,
+      output_scale, output_zero_point, conv_params, filter_packed_type);
+}
+
 // Xtensa kernels do not support float activations., and the corresponding tests
 // are disabled. As a result, helper functions that are only needed for float
 // kernel tests also need to be ifdef'd out to avoid build errors due to unused
@@ -989,4 +1025,47 @@
       output_scale, output_zero_point, &conv_params);
 }
 
+TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannelInt16InputInt8Filter) {
+  const int input_elements = 12;
+  int input_shape[] = {4, 1, 3, 2, 2};
+  const float input_values[] = {-547, 108, -682, 540,  -161, -539, 9,    -482,
+                                -859, 84,  153,  -726, 523,  702,  -172, -936};
+  const int filter_elements = 16;
+  int filter_shape[] = {4, 1, 2, 2, 4};
+  const float filter_values[] = {1, 2, 3, 4, -9, 10,  -11, 12,
+                                 5, 6, 7, 8, 13, -14, 15,  -16};
+  const int bias_elements = 4;
+  int bias_shape[] = {4, 1, 1, 1, 4};
+  const int output_elements = 8;
+  const float bias_values[] = {1, 2, 3, 4};
+  const float golden[] = {
+      4894, -9009, -16596, 10268, -2564, -7483, -6599, 4356,
+  };
+  int output_shape[] = {4, 1, 2, 1, 4};
+  const int output_dims_count = 8;
+  int16_t output_data[output_dims_count];
+
+  const float input_scale = 0.5;
+  const float output_scale = 1.0f;
+  const int input_zero_point = 0;
+  const int output_zero_point = 0;
+
+  int16_t input_quantized[input_elements];
+  int8_t filter_quantized[filter_elements];
+  int64_t bias_quantized[bias_elements];
+  int16_t golden_quantized[output_elements];
+
+  TfLiteDepthwiseConvParams conv_params;
+  conv_params.activation = kTfLiteActNone;
+  conv_params.dilation_width_factor = 1;
+  conv_params.dilation_height_factor = 1;
+  conv_params.stride_height = 1;
+  conv_params.stride_width = 1;
+
+  tflite::testing::TestDepthwiseConvQuantizedPerChannel(
+      input_shape, input_values, input_quantized, input_scale, input_zero_point,
+      filter_shape, filter_values, filter_quantized, bias_shape, bias_values,
+      bias_quantized, output_shape, golden, golden_quantized, output_data,
+      output_scale, output_zero_point, &conv_params);
+}
 TF_LITE_MICRO_TESTS_END
diff --git a/tensorflow/lite/micro/kernels/xtensa/depthwise_conv.cc b/tensorflow/lite/micro/kernels/xtensa/depthwise_conv.cc
index 02ea871..f3acb8d 100644
--- a/tensorflow/lite/micro/kernels/xtensa/depthwise_conv.cc
+++ b/tensorflow/lite/micro/kernels/xtensa/depthwise_conv.cc
@@ -48,6 +48,18 @@
 
 TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
   TF_LITE_ENSURE_OK(context, DepthwiseConvPrepare(context, node));
+  MicroContext* micro_context = GetMicroContext(context);
+  TfLiteTensor* input =
+      micro_context->AllocateTempInputTensor(node, kConvInputTensor);
+  TF_LITE_ENSURE(context, input != nullptr);
+
+  // For int16 input, only fallback to the reference kernel is used
+  // so there is no need to prepare the Hifi/Vision kernel.
+  if (input->type == kTfLiteInt16) {
+    micro_context->DeallocateTempTfLiteTensor(input);
+    return kTfLiteOk;
+  }
+  micro_context->DeallocateTempTfLiteTensor(input);
 
 #if defined(HIFI4) || defined(HIFI5)
   TF_LITE_ENSURE_OK(context, DepthwiseConvPrepareHifi(context, node));
@@ -114,6 +126,31 @@
       }
       break;
     }
+    case kTfLiteInt16: {
+      switch (filter->type) {
+        case kTfLiteInt8: {
+          reference_integer_ops::DepthwiseConvPerChannel(
+              DepthwiseConvParamsQuantized(params, op_data.reference_op_data),
+              op_data.reference_op_data.per_channel_output_multiplier,
+              op_data.reference_op_data.per_channel_output_shift,
+              tflite::micro::GetTensorShape(input),
+              tflite::micro::GetTensorData<int16_t>(input),
+              tflite::micro::GetTensorShape(filter),
+              tflite::micro::GetTensorData<int8_t>(&filter_int8),
+              tflite::micro::GetTensorShape(bias),
+              tflite::micro::GetOptionalTensorData<int64_t>(bias),
+              tflite::micro::GetTensorShape(output),
+              tflite::micro::GetTensorData<int16_t>(output));
+          break;
+        }
+        default:
+          MicroPrintf("Filter type %s (%d) for input type %s not supported.",
+                      TfLiteTypeGetName(filter->type), filter->type,
+                      TfLiteTypeGetName(input->type));
+          return kTfLiteError;
+      }
+      break;
+    }
     default:
       MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type),
                   input->type);