apps_mlearning_tflite-micro/tensorflow/lite/micro/micro_resource_variable.cc

159 lines
6.0 KiB
C++

/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/micro/micro_resource_variable.h"
#include <cstring>
#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/kernels/internal/compatibility.h"
#include "tensorflow/lite/micro/memory_helpers.h"
#include "tensorflow/lite/micro/micro_log.h"
#include "tensorflow/lite/micro/micro_utils.h"
namespace tflite {
namespace {} // namespace
MicroResourceVariables* MicroResourceVariables::Create(
MicroAllocator* allocator, int max_num_variables) {
TFLITE_DCHECK(allocator != nullptr);
uint8_t* allocator_buffer = static_cast<uint8_t*>(
allocator->AllocatePersistentBuffer(sizeof(MicroResourceVariables)));
MicroResourceVariable* variable_array =
static_cast<MicroResourceVariable*>(allocator->AllocatePersistentBuffer(
sizeof(MicroResourceVariable) * max_num_variables));
MicroResourceVariables* variables = new (allocator_buffer)
MicroResourceVariables(variable_array, max_num_variables);
return variables;
}
int MicroResourceVariables::CreateIdIfNoneFound(const char* container,
const char* shared_name) {
int resource_id = FindId(container, shared_name);
if (resource_id >= 0) {
return resource_id;
}
// no existing variable found for the given container and shared name pair.
if (num_resource_variables_ >= max_variable_count_) {
MicroPrintf(
"Failed to allocate resource variable. Maximum resource variable count "
"(%d) "
"reached.",
max_variable_count_);
return -1;
}
resource_id = num_resource_variables_++;
resource_variables_[resource_id].container = container;
resource_variables_[resource_id].shared_name = shared_name;
resource_variables_[resource_id].resource_buffer = nullptr;
resource_variables_[resource_id].bytes = 0;
resource_variables_[resource_id].default_value = 0;
return resource_id;
}
TfLiteStatus MicroResourceVariables::Read(int id,
const TfLiteEvalTensor* tensor) {
if (id < 0 || id >= num_resource_variables_) {
MicroPrintf("Attempting to read non-existent resource variable %d", id);
return kTfLiteError;
}
MicroResourceVariable variable = resource_variables_[id];
TFLITE_DCHECK(EvalTensorBytes(tensor) == variable.bytes);
TFLITE_DCHECK(variable.resource_buffer != nullptr);
memcpy(tensor->data.raw, variable.resource_buffer, variable.bytes);
return kTfLiteOk;
}
TfLiteStatus MicroResourceVariables::Allocate(int id, TfLiteContext* context,
const TfLiteTensor* tensor) {
if (id < 0 || id >= num_resource_variables_) {
MicroPrintf("Attempting to read non-existent resource variable %d", id);
return kTfLiteError;
}
MicroResourceVariable& variable = resource_variables_[id];
if (variable.resource_buffer == nullptr) {
variable.bytes = tensor->bytes;
variable.resource_buffer =
context->AllocatePersistentBuffer(context, tensor->bytes);
if (variable.resource_buffer == nullptr) {
MicroPrintf("Failed to allocate resource buffer.");
return kTfLiteError;
}
// Set resource buffers to the zero_point by default. Buffers can be
// initialized to nonzero values using ASSIGN_VARIABLE.
// See comment#2 in b/269648474 for more details why we use zero_point.
if (tensor->quantization.params != nullptr) {
auto* quantization_data = reinterpret_cast<TfLiteAffineQuantization*>(
tensor->quantization.params);
int8_t zero_point = quantization_data->zero_point[0].data[0];
variable.default_value = zero_point;
}
// TODO(b/269669735): Explains why casting zero_point to int8 and memset.
memset(variable.resource_buffer, variable.default_value, variable.bytes);
}
return kTfLiteOk;
}
TfLiteStatus MicroResourceVariables::Assign(int id,
const TfLiteEvalTensor* tensor) {
if (id < 0 || id >= num_resource_variables_) {
MicroPrintf("Attempting to read non-existent resource variable %d", id);
return kTfLiteError;
}
MicroResourceVariable variable = resource_variables_[id];
if (variable.resource_buffer == nullptr) {
MicroPrintf(
"Attempting to assign from a TfLiteEvalTensor before the resource "
"buffer has been allocated. Make sure to call AssignResourceVariable "
"with a TfLiteTensor first.");
return kTfLiteError;
}
TFLITE_DCHECK(EvalTensorBytes(tensor) == variable.bytes);
memcpy(variable.resource_buffer, tensor->data.raw, variable.bytes);
return kTfLiteOk;
}
TfLiteStatus MicroResourceVariables::ResetAll() {
for (int i = 0; i < num_resource_variables_; i++) {
MicroResourceVariable variable = resource_variables_[i];
// TODO(b/269669735): Explains why casting zero_point to int8 and memset.
memset(variable.resource_buffer, variable.default_value, variable.bytes);
}
return kTfLiteOk;
}
int MicroResourceVariables::FindId(const char* container,
const char* shared_name) {
for (int i = 0; i < num_resource_variables_; i++) {
// Some TFLite flatbuffers contain null container names to save space.
if ((container == nullptr ||
!strcmp(container, resource_variables_[i].container)) &&
!strcmp(shared_name, resource_variables_[i].shared_name)) {
return i;
}
}
return -1;
}
} // namespace tflite