# Copyright 2023 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. # ============================================================================== """ Tensor class """ from typing import Dict, Optional import string import textwrap from tflite_micro.codegen import utils from tflite_micro.tensorflow.lite.python import schema_py_generated as schema_fb _TENSOR_TYPES: Dict[int, str] = { schema_fb.TensorType.FLOAT16: "kTfLiteFloat16", schema_fb.TensorType.FLOAT32: "kTfLiteFloat32", schema_fb.TensorType.FLOAT64: "kTfLiteFloat64", schema_fb.TensorType.INT16: "kTfLiteInt16", schema_fb.TensorType.UINT16: "kTfLiteUInt16", schema_fb.TensorType.INT32: "kTfLiteInt32", schema_fb.TensorType.UINT32: "kTfLiteUInt32", schema_fb.TensorType.UINT8: "kTfLiteUInt8", schema_fb.TensorType.INT8: "kTfLiteInt8", schema_fb.TensorType.INT64: "kTfLiteInt64", schema_fb.TensorType.UINT64: "kTfLiteUInt64", schema_fb.TensorType.STRING: "kTfLiteString", schema_fb.TensorType.BOOL: "kTfLiteBool", schema_fb.TensorType.COMPLEX64: "kTfLiteComplex64", schema_fb.TensorType.COMPLEX128: "kTfLiteComplex128", schema_fb.TensorType.RESOURCE: "kTfLiteResource", schema_fb.TensorType.VARIANT: "kTfLiteVariant", schema_fb.TensorType.INT4: "kTfLiteInt4", } class Buffer(object): """ This buffer could be either a static array or a pointer into the arena """ def __init__(self, buffer_name: str, buffer: schema_fb.BufferT): # TODO(rjascani): Get arena allocation offsets from preprocessor self._buffer_name = buffer_name self._buffer = buffer @property def address(self) -> str: if self._buffer is None or self._buffer.data is None: # TODO(rjascani): This needs to point into the arena return f"nullptr /* {self._buffer_name} */" return f"&{self._buffer_name}" def generate_c_buffer_array(self, indent: str) -> str: if self._buffer is None or self._buffer.data is None: return f"// {self._buffer_name} is located in the arena\n" buffer_template = string.Template( "alignas(16) uint8_t ${buffer_name}[${size}] = {\n" "${body}\n" "};\n") byte_strs = ['0x{:02X}'.format(b) for b in self._buffer.data] lines = [] for byte_strs_for_line in utils.split_into_chunks(byte_strs, 12): bytes_segment = ', '.join(byte_strs_for_line) lines.append(f' {bytes_segment},') return textwrap.indent( buffer_template.substitute(buffer_name=self._buffer_name, size=len(self._buffer.data), body='\n'.join(lines)), indent) class Tensor(object): def __init__(self, buffer: Buffer, tensor: schema_fb.TensorT): self._buffer = buffer self._tensor: schema_fb.TensorT = tensor @property def buffer_index(self) -> bool: return self._tensor.buffer @property def buffer(self) -> Buffer: return self._buffer @property def has_shape(self) -> bool: return self._tensor.shape is not None @property def needs_zero_length_int_array(self) -> bool: return not self.has_shape def generate_c_tensor_dims(self, type_name: str, tensor_name: str) -> str: if not self.has_shape: return f"// No data dims necessary for {tensor_name}" return utils.IntArray(self._tensor.shape).generate_c_struct( type_name + "Dims", tensor_name + "_dims") def generate_c_tensor_init(self, tflite_tensor_name: str, tensor_name: str) -> str: init_template = string.Template( "${tflite_tensor_name} = TfLiteEvalTensor{\n" " .data = {.data = static_cast(${data})},\n" " .dims = ${dims},\n" " .type = ${tflite_type}};") dims = "reinterpret_cast(&{})".format( f"{tensor_name}_dims" if self._tensor. shape is not None else "zero_length_int_array") return init_template.substitute( tflite_tensor_name=tflite_tensor_name, tensor_name=tensor_name, data=self._buffer.address, dims=dims, tflite_type=_TENSOR_TYPES[self._tensor.type])