mirror of
https://github.com/vee1e/tflite-micro.git
synced 2026-09-01 17:57:27 +00:00
Add 16bit xtensa depthwise conv kernel support (#3481)
* Added 16x8 xtensa depthwise conv kernel * Added int16 support only for HIFI5 * Code formatting
This commit is contained in:
parent
f2b2b3f51c
commit
f5302ed4fa
3 changed files with 164 additions and 21 deletions
|
|
@ -52,13 +52,14 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
|||
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.
|
||||
#ifndef HIFI5
|
||||
// Int16 input is only supported by HIFI5 for now.
|
||||
// So there is no need to prepare the Hifi/Vision kernel for other targets.
|
||||
if (input->type == kTfLiteInt16) {
|
||||
micro_context->DeallocateTempTfLiteTensor(input);
|
||||
return kTfLiteOk;
|
||||
}
|
||||
#endif
|
||||
micro_context->DeallocateTempTfLiteTensor(input);
|
||||
|
||||
#if defined(HIFI3) || defined(HIFI4) || defined(HIFI5)
|
||||
|
|
@ -110,8 +111,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||
switch (filter_int8.type) {
|
||||
case kTfLiteInt8: {
|
||||
#if defined(HIFI3) || defined(HIFI4) || defined(HIFI5)
|
||||
DepthwiseConvEvalHifi(context, node, params, op_data, input,
|
||||
&filter_int8, bias, output);
|
||||
DepthwiseConvEvalHifiInt8(context, node, params, op_data, input,
|
||||
&filter_int8, bias, output);
|
||||
#elif defined(VISION_P6)
|
||||
DepthwiseConvEvalVision(context, node, params, op_data, input,
|
||||
&filter_int8, bias, output);
|
||||
|
|
@ -151,6 +152,10 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||
case kTfLiteInt16: {
|
||||
switch (filter->type) {
|
||||
case kTfLiteInt8: {
|
||||
#if defined(HIFI5)
|
||||
DepthwiseConvEvalHifiInt16(context, node, params, op_data, input,
|
||||
filter, bias, output);
|
||||
#else
|
||||
reference_integer_ops::DepthwiseConvPerChannel(
|
||||
DepthwiseConvParamsQuantized(params, op_data.reference_op_data),
|
||||
op_data.reference_op_data.per_channel_output_multiplier,
|
||||
|
|
@ -173,6 +178,7 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||
#endif // USE_TFLM_COMPRESSION
|
||||
tflite::micro::GetTensorShape(output),
|
||||
tflite::micro::GetTensorData<int16_t>(output));
|
||||
#endif // defined(HIFI5)
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -50,8 +50,6 @@ TfLiteStatus DepthwiseConvPrepareHifi(TfLiteContext* context,
|
|||
micro_context->AllocateTempInputTensor(node, kConvWeightsTensor);
|
||||
TF_LITE_ENSURE(context, filter != nullptr);
|
||||
|
||||
TF_LITE_ENSURE_EQ(context, input->type, kTfLiteInt8);
|
||||
|
||||
const RuntimeShape& input_shape = GetTensorShape(input);
|
||||
const RuntimeShape& filter_shape = GetTensorShape(filter);
|
||||
const RuntimeShape& output_shape = GetTensorShape(output);
|
||||
|
|
@ -90,13 +88,13 @@ TfLiteStatus DepthwiseConvPrepareHifi(TfLiteContext* context,
|
|||
return kTfLiteOk;
|
||||
}
|
||||
|
||||
TfLiteStatus DepthwiseConvEvalHifi(TfLiteContext* context, TfLiteNode* node,
|
||||
const TfLiteDepthwiseConvParams& params,
|
||||
const XtensaDepthwiseConvOpData& data,
|
||||
const TfLiteEvalTensor* input,
|
||||
const TfLiteEvalTensor* filter,
|
||||
const TfLiteEvalTensor* bias,
|
||||
TfLiteEvalTensor* output) {
|
||||
TfLiteStatus DepthwiseConvEvalHifiInt8(TfLiteContext* context, TfLiteNode* node,
|
||||
const TfLiteDepthwiseConvParams& params,
|
||||
const XtensaDepthwiseConvOpData& data,
|
||||
const TfLiteEvalTensor* input,
|
||||
const TfLiteEvalTensor* filter,
|
||||
const TfLiteEvalTensor* bias,
|
||||
TfLiteEvalTensor* output) {
|
||||
#ifdef USE_TFLM_COMPRESSION
|
||||
|
||||
MicroContext* micro_context = GetMicroContext(context);
|
||||
|
|
@ -217,5 +215,135 @@ TfLiteStatus DepthwiseConvEvalHifi(TfLiteContext* context, TfLiteNode* node,
|
|||
|
||||
return kTfLiteOk;
|
||||
}
|
||||
|
||||
TfLiteStatus DepthwiseConvEvalHifiInt16(TfLiteContext* context,
|
||||
TfLiteNode* node,
|
||||
const TfLiteDepthwiseConvParams& params,
|
||||
const XtensaDepthwiseConvOpData& data,
|
||||
const TfLiteEvalTensor* input,
|
||||
const TfLiteEvalTensor* filter,
|
||||
const TfLiteEvalTensor* bias,
|
||||
TfLiteEvalTensor* output) {
|
||||
#ifdef USE_TFLM_COMPRESSION
|
||||
|
||||
MicroContext* micro_context = GetMicroContext(context);
|
||||
|
||||
const CompressionTensorData* filter_comp_td =
|
||||
micro_context->GetTensorCompressionData(node,
|
||||
kDepthwiseConvWeightsTensor);
|
||||
const CompressionTensorData* bias_comp_td =
|
||||
micro_context->GetTensorCompressionData(node, kDepthwiseConvBiasTensor);
|
||||
|
||||
#endif // USE_TFLM_COMPRESSION
|
||||
|
||||
// If dilation is not required use the optimized NN Library kernel.
|
||||
// Otherwise call the reference implementation.
|
||||
if ((params.dilation_width_factor == 1) &&
|
||||
(params.dilation_height_factor == 1) && bias != nullptr) {
|
||||
const int stride_width = params.stride_width;
|
||||
const int stride_height = params.stride_height;
|
||||
const int pad_width = data.reference_op_data.padding.width;
|
||||
const int pad_height = data.reference_op_data.padding.height;
|
||||
const int depth_multiplier = params.depth_multiplier;
|
||||
const int32_t output_activation_min =
|
||||
data.reference_op_data.output_activation_min;
|
||||
const int32_t output_activation_max =
|
||||
data.reference_op_data.output_activation_max;
|
||||
TFLITE_DCHECK_LE(output_activation_min, output_activation_max);
|
||||
|
||||
const RuntimeShape& input_shape = tflite::micro::GetTensorShape(input);
|
||||
const RuntimeShape& filter_shape = tflite::micro::GetTensorShape(filter);
|
||||
const RuntimeShape& output_shape = tflite::micro::GetTensorShape(output);
|
||||
const RuntimeShape& bias_shape = tflite::micro::GetTensorShape(bias);
|
||||
TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4);
|
||||
TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4);
|
||||
TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4);
|
||||
|
||||
const int batches = MatchingDim(input_shape, 0, output_shape, 0);
|
||||
const int output_depth = MatchingDim(filter_shape, 3, output_shape, 3);
|
||||
const int input_height = input_shape.Dims(1);
|
||||
const int input_width = input_shape.Dims(2);
|
||||
const int input_depth = input_shape.Dims(3);
|
||||
const int filter_height = filter_shape.Dims(1);
|
||||
const int filter_width = filter_shape.Dims(2);
|
||||
const int output_height = output_shape.Dims(1);
|
||||
const int output_width = output_shape.Dims(2);
|
||||
TFLITE_DCHECK_EQ(output_depth, input_depth * depth_multiplier);
|
||||
TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth);
|
||||
|
||||
const int16_t* input_data = tflite::micro::GetTensorData<int16_t>(input);
|
||||
#ifdef USE_TFLM_COMPRESSION
|
||||
const int8_t* filter_data = tflite::micro::GetTensorData<int8_t>(
|
||||
micro_context, filter, filter_comp_td,
|
||||
data.reference_op_data.weights_scratch_index);
|
||||
const int64_t* bias_data = tflite::micro::GetTensorData<int64_t>(
|
||||
micro_context, bias, bias_comp_td,
|
||||
data.reference_op_data.bias_scratch_index);
|
||||
#else // USE_TFLM_COMPRESSION
|
||||
const int8_t* filter_data = tflite::micro::GetTensorData<int8_t>(filter);
|
||||
const int64_t* bias_data = tflite::micro::GetTensorData<int64_t>(bias);
|
||||
#endif // USE_TFLM_COMPRESSION
|
||||
int16_t* output_data = tflite::micro::GetTensorData<int16_t>(output);
|
||||
|
||||
int32_t input_data_format = 0;
|
||||
int32_t output_data_format = 0;
|
||||
|
||||
uint8_t* p_scratch = static_cast<uint8_t*>(
|
||||
context->GetScratchBuffer(context, data.scratch_tensor_index));
|
||||
|
||||
for (int i = 0; i < batches; i++) {
|
||||
TF_LITE_ENSURE_EQ(
|
||||
context,
|
||||
xa_nn_conv2d_depthwise_per_chan_sym8sxsym16s(
|
||||
&output_data[i * output_height * output_width * output_depth],
|
||||
filter_data,
|
||||
&input_data[i * input_height * input_width * input_depth],
|
||||
bias_data, input_height, input_width, input_depth, filter_height,
|
||||
filter_width, depth_multiplier, stride_width, stride_height,
|
||||
pad_width, pad_height, output_height, output_width,
|
||||
-data.reference_op_data.input_zero_point,
|
||||
data.reference_op_data.per_channel_output_multiplier,
|
||||
data.reference_op_data.per_channel_output_shift,
|
||||
data.reference_op_data.output_zero_point, input_data_format,
|
||||
output_data_format, p_scratch),
|
||||
0);
|
||||
}
|
||||
|
||||
int out_length = batches * output_height * output_width * output_depth;
|
||||
TF_LITE_ENSURE_EQ(context,
|
||||
xa_nn_vec_activation_min_max_16_16(
|
||||
output_data, output_data, output_activation_min,
|
||||
output_activation_max, out_length),
|
||||
0);
|
||||
|
||||
return kTfLiteOk;
|
||||
}
|
||||
|
||||
reference_integer_ops::DepthwiseConvPerChannel(
|
||||
DepthwiseConvParamsQuantized(params, data.reference_op_data),
|
||||
data.reference_op_data.per_channel_output_multiplier,
|
||||
data.reference_op_data.per_channel_output_shift,
|
||||
tflite::micro::GetTensorShape(input),
|
||||
tflite::micro::GetTensorData<int16_t>(input),
|
||||
tflite::micro::GetTensorShape(filter),
|
||||
#ifdef USE_TFLM_COMPRESSION
|
||||
tflite::micro::GetTensorData<int8_t>(
|
||||
micro_context, filter, filter_comp_td,
|
||||
data.reference_op_data.weights_scratch_index),
|
||||
tflite::micro::GetTensorShape(bias),
|
||||
tflite::micro::GetOptionalTensorData<int64_t>(
|
||||
micro_context, bias, bias_comp_td,
|
||||
data.reference_op_data.bias_scratch_index),
|
||||
#else // USE_TFLM_COMPRESSION
|
||||
tflite::micro::GetTensorData<int8_t>(filter),
|
||||
tflite::micro::GetTensorShape(bias),
|
||||
tflite::micro::GetOptionalTensorData<int64_t>(bias),
|
||||
#endif // USE_TFLM_COMPRESSION
|
||||
tflite::micro::GetTensorShape(output),
|
||||
tflite::micro::GetTensorData<int16_t>(output));
|
||||
|
||||
return kTfLiteOk;
|
||||
}
|
||||
|
||||
} // namespace tflite
|
||||
#endif // defined(HIFI3) ||defined(HIFI4) || defined(HIFI5)
|
||||
|
|
|
|||
|
|
@ -42,13 +42,22 @@ struct XtensaDepthwiseConvOpData {
|
|||
#if defined(HIFI3) || defined(HIFI4) || defined(HIFI5)
|
||||
TfLiteStatus DepthwiseConvPrepareHifi(TfLiteContext* context, TfLiteNode* node);
|
||||
|
||||
TfLiteStatus DepthwiseConvEvalHifi(TfLiteContext* context, TfLiteNode* node,
|
||||
const TfLiteDepthwiseConvParams& params,
|
||||
const XtensaDepthwiseConvOpData& data,
|
||||
const TfLiteEvalTensor* input,
|
||||
const TfLiteEvalTensor* filter,
|
||||
const TfLiteEvalTensor* bias,
|
||||
TfLiteEvalTensor* output);
|
||||
TfLiteStatus DepthwiseConvEvalHifiInt8(TfLiteContext* context, TfLiteNode* node,
|
||||
const TfLiteDepthwiseConvParams& params,
|
||||
const XtensaDepthwiseConvOpData& data,
|
||||
const TfLiteEvalTensor* input,
|
||||
const TfLiteEvalTensor* filter,
|
||||
const TfLiteEvalTensor* bias,
|
||||
TfLiteEvalTensor* output);
|
||||
|
||||
TfLiteStatus DepthwiseConvEvalHifiInt16(TfLiteContext* context,
|
||||
TfLiteNode* node,
|
||||
const TfLiteDepthwiseConvParams& params,
|
||||
const XtensaDepthwiseConvOpData& data,
|
||||
const TfLiteEvalTensor* input,
|
||||
const TfLiteEvalTensor* filter,
|
||||
const TfLiteEvalTensor* bias,
|
||||
TfLiteEvalTensor* output);
|
||||
|
||||
TfLiteStatus DepthwiseConvReferenceEvalInt8(TfLiteContext* context,
|
||||
TfLiteNode* node);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue