tensorflow/lite/kernels/conv.cc
static TfLiteStatus AllocateTemporaryTensorsIfRequired(TfLiteContext* context,
                                                       TfLiteNode* node,
                                                       bool is_hybrid,
                                                       bool is_per_channel,
                                                       KernelType kernel_type) {
  auto* params = reinterpret_cast<TfLiteConvParams*>(node->builtin_data);
  OpData* data = reinterpret_cast<OpData*>(node->user_data);

  TF_LITE_ENSURE(context, node->inputs->size >= 2);
  const TfLiteTensor* input = GetInput(context, node, 0);
  const TfLiteTensor* filter = GetInput(context, node, 1);

  // If we're using the optimized multithreaded EigenTensor implementation of
  // convolution, it expects the filter weights to be transposed compared to
  // the normal TF Lite buffer format. Typical TF Lite weights are
  // [filter_count, filter_height, filter_width, input_depth], but for the float
  // implementation we need them as [filter_height, filter_width, input_depth,
  // filter_count]. We get to that format by transposing, and create a temporary
  // buffer to store the results.
  // This path is only used for float processing, so only create the buffer if
  // we're running with that data type.
  data->need_hwcn_weights =
      input->type == kTfLiteFloat32 && data->supports_multithreaded_kernel;

  // We don't always need to allocate im2col. It is only used in some versions
  // of the optimized Conv. This test just mimics something that happens inside
  // optimized_ops.h, in order to avoid a DCHECK(!im2col_data).
  data->need_im2col =
      IsIm2ColRequired(input, params, filter, data, is_hybrid, kernel_type);

  int temporaries_count = 0;
  if (data->need_im2col) {
    data->im2col_index = temporaries_count;
    if (data->im2col_id == kTensorNotAllocated) {
      context->AddTensors(context, 1, &data->im2col_id);
    }
    ++temporaries_count;
  }
  if (data->need_hwcn_weights) {
    data->hwcn_weights_index = temporaries_count;
    if (data->hwcn_weights_id == kTensorNotAllocated) {
      context->AddTensors(context, 1, &data->hwcn_weights_id);
    }
    ++temporaries_count;
  }

  if (is_hybrid) {
    // Allocate tensor to store the on-the-fly quantized inputs.
    data->input_quantized_index = temporaries_count;
    if (data->input_quantized_id == kTensorNotAllocated) {
      TF_LITE_ENSURE_OK(
          context, context->AddTensors(context, 1, &data->input_quantized_id));
    }
    ++temporaries_count;

    // Allocate tensor to store the quantization params computed during
    // on-the-fly input quantization.
    data->scaling_factors_index = temporaries_count;
    if (data->scaling_factors_id == kTensorNotAllocated) {
      TF_LITE_ENSURE_OK(
          context, context->AddTensors(context, 1, &data->scaling_factors_id));
    }
    ++temporaries_count;

    // Allocate tensor to store the accumulators for the matrix multiply.
    data->accum_scratch_index = temporaries_count;
    if (data->accum_scratch_id == kTensorNotAllocated) {
      TF_LITE_ENSURE_OK(
          context, context->AddTensors(context, 1, &data->accum_scratch_id));
    }
    ++temporaries_count;
    if (is_per_channel) {
      data->input_offset_index = temporaries_count;
      if (data->input_offset_id == kTensorNotAllocated) {
        TF_LITE_ENSURE_OK(
            context, context->AddTensors(context, 1, &data->input_offset_id));
      }
      ++temporaries_count;

      data->row_sums_index = temporaries_count;
      if (data->row_sums_id == kTensorNotAllocated) {
        TF_LITE_ENSURE_OK(context,
                          context->AddTensors(context, 1, &data->row_sums_id));
      }
      ++temporaries_count;
    }
  }

  TfLiteIntArrayFree(node->temporaries);
  node->temporaries = TfLiteIntArrayCreate(temporaries_count);

  return kTfLiteOk;
}
// Allocate temporary tensors (`im2col`, `hwcn_weights` if necessary).
// Note: `context->AddTensors` might invalidate pointers to existing tensors.
// Therefore the logic to add tensors are isolated into this function.
Allocate temporary tensors (`im2col`, `hwcn_weights` if necessary).
Note: `context->AddTensors` might invalidate pointers to existing tensors.
Therefore the logic to add tensors are isolated into this function.
Allocate temporary tensors ( ` im2col ` ` hwcn_weights ` if necessary ) . Note : ` context - > AddTensors ` might invalidate pointers to existing tensors . Therefore the logic to add tensors are isolated into this function .
static TfLiteStatus AllocateTemporaryTensorsIfRequired(TfLiteContext* context,
                                                       TfLiteNode* node,
                                                       bool is_hybrid,
                                                       bool is_per_channel,
                                                       KernelType kernel_type) {
  auto* params = reinterpret_cast<TfLiteConvParams*>(node->builtin_data);
  OpData* data = reinterpret_cast<OpData*>(node->user_data);
  TF_LITE_ENSURE(context, node->inputs->size >= 2);
  const TfLiteTensor* input = GetInput(context, node, 0);
  const TfLiteTensor* filter = GetInput(context, node, 1);
  data->need_hwcn_weights =
      input->type == kTfLiteFloat32 && data->supports_multithreaded_kernel;
  data->need_im2col =
      IsIm2ColRequired(input, params, filter, data, is_hybrid, kernel_type);
  int temporaries_count = 0;
  if (data->need_im2col) {
    data->im2col_index = temporaries_count;
    if (data->im2col_id == kTensorNotAllocated) {
      context->AddTensors(context, 1, &data->im2col_id);
    }
    ++temporaries_count;
  }
  if (data->need_hwcn_weights) {
    data->hwcn_weights_index = temporaries_count;
    if (data->hwcn_weights_id == kTensorNotAllocated) {
      context->AddTensors(context, 1, &data->hwcn_weights_id);
    }
    ++temporaries_count;
  }
  if (is_hybrid) {
    data->input_quantized_index = temporaries_count;
    if (data->input_quantized_id == kTensorNotAllocated) {
      TF_LITE_ENSURE_OK(
          context, context->AddTensors(context, 1, &data->input_quantized_id));
    }
    ++temporaries_count;
    data->scaling_factors_index = temporaries_count;
    if (data->scaling_factors_id == kTensorNotAllocated) {
      TF_LITE_ENSURE_OK(
          context, context->AddTensors(context, 1, &data->scaling_factors_id));
    }
    ++temporaries_count;
    data->accum_scratch_index = temporaries_count;
    if (data->accum_scratch_id == kTensorNotAllocated) {
      TF_LITE_ENSURE_OK(
          context, context->AddTensors(context, 1, &data->accum_scratch_id));
    }
    ++temporaries_count;
    if (is_per_channel) {
      data->input_offset_index = temporaries_count;
      if (data->input_offset_id == kTensorNotAllocated) {
        TF_LITE_ENSURE_OK(
            context, context->AddTensors(context, 1, &data->input_offset_id));
      }
      ++temporaries_count;
      data->row_sums_index = temporaries_count;
      if (data->row_sums_id == kTensorNotAllocated) {
        TF_LITE_ENSURE_OK(context,
                          context->AddTensors(context, 1, &data->row_sums_id));
      }
      ++temporaries_count;
    }
  }
  TfLiteIntArrayFree(node->temporaries);
  node->temporaries = TfLiteIntArrayCreate(temporaries_count);
  return kTfLiteOk;
}
static TfLiteStatus AllocateTemporaryTensorsIfRequired ( TfLiteContext * context , TfLiteNode * node , bool is_hybrid , bool is_per_channel , KernelType kernel_type ) { auto * params = reinterpret_cast < TfLiteConvParams * > ( node -> builtin_data ) ; OpData * data = reinterpret_cast < OpData * > ( node -> user_data ) ; TF_LITE_ENSURE ( context , node -> inputs -> size >= 2 ) ; const TfLiteTensor * input = GetInput ( context , node , 0 ) ; const TfLiteTensor * filter = GetInput ( context , node , 1 ) ; data -> need_hwcn_weights = input -> type == kTfLiteFloat32 && data -> supports_multithreaded_kernel ; data -> need_im2col = IsIm2ColRequired ( input , params , filter , data , is_hybrid , kernel_type ) ; int temporaries_count = 0 ; if ( data -> need_im2col ) { data -> im2col_index = temporaries_count ; if ( data -> im2col_id == kTensorNotAllocated ) { context -> AddTensors ( context , 1 , & data -> im2col_id ) ; } ++ temporaries_count ; } if ( data -> need_hwcn_weights ) { data -> hwcn_weights_index = temporaries_count ; if ( data -> hwcn_weights_id == kTensorNotAllocated ) { context -> AddTensors ( context , 1 , & data -> hwcn_weights_id ) ; } ++ temporaries_count ; } if ( is_hybrid ) { data -> input_quantized_index = temporaries_count ; if ( data -> input_quantized_id == kTensorNotAllocated ) { TF_LITE_ENSURE_OK ( context , context -> AddTensors ( context , 1 , & data -> input_quantized_id ) ) ; } ++ temporaries_count ; data -> scaling_factors_index = temporaries_count ; if ( data -> scaling_factors_id == kTensorNotAllocated ) { TF_LITE_ENSURE_OK ( context , context -> AddTensors ( context , 1 , & data -> scaling_factors_id ) ) ; } ++ temporaries_count ; data -> accum_scratch_index = temporaries_count ; if ( data -> accum_scratch_id == kTensorNotAllocated ) { TF_LITE_ENSURE_OK ( context , context -> AddTensors ( context , 1 , & data -> accum_scratch_id ) ) ; } ++ temporaries_count ; if ( is_per_channel ) { data -> input_offset_index = temporaries_count ; if ( data -> input_offset_id == kTensorNotAllocated ) { TF_LITE_ENSURE_OK ( context , context -> AddTensors ( context , 1 , & data -> input_offset_id ) ) ; } ++ temporaries_count ; data -> row_sums_index = temporaries_count ; if ( data -> row_sums_id == kTensorNotAllocated ) { TF_LITE_ENSURE_OK ( context , context -> AddTensors ( context , 1 , & data -> row_sums_id ) ) ; } ++ temporaries_count ; } } TfLiteIntArrayFree ( node -> temporaries ) ; node -> temporaries = TfLiteIntArrayCreate ( temporaries_count ) ; return kTfLiteOk ; }
Allocate temporary tensors (`im2col`, `hwcn_weights` if necessary).
Allocate temporary tensors ( ` im2col ` ` hwcn_weights ` if necessary ) .
// If we're using the optimized multithreaded EigenTensor implementation of // convolution, it expects the filter weights to be transposed compared to // the normal TF Lite buffer format. Typical TF Lite weights are // [filter_count, filter_height, filter_width, input_depth], but for the float // implementation we need them as [filter_height, filter_width, input_depth, // filter_count]. We get to that format by transposing, and create a temporary // buffer to store the results. // This path is only used for float processing, so only create the buffer if // we're running with that data type. // We don't always need to allocate im2col. It is only used in some versions // of the optimized Conv. This test just mimics something that happens inside // optimized_ops.h, in order to avoid a DCHECK(!im2col_data). // Allocate tensor to store the on-the-fly quantized inputs. // Allocate tensor to store the quantization params computed during // on-the-fly input quantization. // Allocate tensor to store the accumulators for the matrix multiply.