# pylint: disable=redefined-builtin
from __future__ import annotations
from typing import List, Tuple, Dict, TypeVar
import numpy as np
from . import tflite_schema as _tflite_schema_fb
from .tflite_schema import BuiltinOperator as TfliteOpCode
from .tflite_tensor import TfliteTensor
from .tflite_types import (
TfliteActivation,
TflitePadding,
TfliteConvParams,
TfliteDepthwiseConvParams,
TfliteTransposeConvParams,
TfliteFullyConnectedParams,
TflitePoolParams
)
TfliteModel = TypeVar('TfliteModel')
[docs]class TfliteLayer:
"""Wrapper for TFLite flatbuffer layer"""
[docs] @staticmethod
def from_flatbuffer(
index:int,
model:TfliteModel,
fb_operation:_tflite_schema_fb.OperatorT
) -> TfliteLayer:
"""Instantiate a TfliteLayer from then given TfliteModel flatbuffer operation"""
fb_opcode = model.flatbuffer_model.operatorCodes[fb_operation.opcodeIndex]
# See: https://github.com/tensorflow/community/pull/285/files
# for why we return the max(DeprecatedBuiltinCode, BuiltinCode)
opcode = max(getattr(fb_opcode, 'deprecatedBuiltinCode', -1), fb_opcode.builtinCode)
opcode_version = fb_opcode.version
if opcode == TfliteOpCode.ADD:
layer_cls = TfliteAddLayer
elif opcode == TfliteOpCode.CONV_2D:
layer_cls = TfliteConv2dLayer
elif opcode == TfliteOpCode.TRANSPOSE_CONV:
layer_cls = TfliteTransposeConvLayer
elif opcode == TfliteOpCode.FULLY_CONNECTED:
layer_cls = TfliteFullyConnectedLayer
elif opcode == TfliteOpCode.DEPTHWISE_CONV_2D:
layer_cls = TfliteDepthwiseConv2dLayer
elif opcode == TfliteOpCode.AVERAGE_POOL_2D or \
opcode == TfliteOpCode.MAX_POOL_2D:
layer_cls = TflitePooling2dLayer
elif opcode == TfliteOpCode.RESHAPE:
layer_cls = TfliteReshapeLayer
elif opcode == TfliteOpCode.QUANTIZE:
layer_cls = TfliteQuantizeLayer
elif opcode == TfliteOpCode.DEQUANTIZE:
layer_cls = TfliteDequantizeLayer
elif opcode == TfliteOpCode.MUL:
layer_cls = TfliteMulLayer
else:
layer_cls = TfliteLayer
return layer_cls(
index=index,
opcode=opcode,
opcode_version=opcode_version,
model=model,
fb_operation=fb_operation
)
[docs] def __init__(
self,
index:int,
opcode:TfliteOpCode,
opcode_version:int,
model:TfliteModel,
fb_operation:_tflite_schema_fb.OperatorT
):
self._index:int = index
self._model:TfliteModel = model
self._opcode:TfliteOpCode = opcode
self._opcode_version:int = opcode_version
self._opcode_str:str = _convert_object_value_to_string(TfliteOpCode(), self.opcode)
self._options = TfliteLayerOptions(
fb_object=fb_operation.builtinOptions,
type=fb_operation.builtinOptionsType
)
self._metadata:Dict[str,object] = {}
self._inputs : List[TfliteTensor] = []
self._outputs : List[TfliteTensor] = []
for i in fb_operation.inputs:
if i >= 0:
self.inputs.append(model.get_tensor(i))
for i in fb_operation.outputs:
if i >= 0:
self.outputs.append(model.get_tensor(i))
def __str__(self):
return self.name
@property
def index(self) -> int:
"""Index of this layer in the model"""
return self._index
@property
def name(self) -> str:
"""Name of current layer as: op<index>-<OpCodeStr>"""
return f'op{self._index}-{self._opcode_str}'
@property
def opcode(self) -> TfliteOpCode:
"""OpCode numeric value"""
return self._opcode
@property
def opcode_str(self) -> str:
"""OpCode as a string"""
return self._opcode_str
@property
def options(self) -> TfliteLayerOptions:
"""Layer-specific options/config"""
return self._options
@property
def model(self) -> TfliteModel:
"""Reference to associated TfliteModel"""
return self._model
@property
def metadata(self) -> Dict[str,object]:
"""Additional key/value data to associated with layer
NOTE: This information is generated by the framework/Python scripts
(i.e. The information does NOT come from the .tflite model)
"""
return self._metadata
@property
def inputs(self) -> List[TfliteTensor]:
"""List of layer input tensor(s)"""
return self._inputs
@property
def n_inputs(self) -> int:
"""Return the number of inputs"""
return len(self._inputs)
@property
def outputs(self) -> List[TfliteTensor]:
"""List of layer output tensor(s)"""
return self._outputs
@property
def n_outputs(self) -> int:
"""Return the number of outputs"""
return len(self._outputs)
[docs] def get_output_tensor(self, index=0) -> TfliteTensor:
"""Layer output tensor as TfliteTensor"""
if index >= self.n_outputs:
raise IndexError(f'Index overflow ({index} >= {self.n_outputs})')
return self._outputs[index]
[docs] def get_output_data(self, index=0) -> np.ndarray:
"""Layer output tensor as np.ndarray"""
if index >= self.n_outputs:
raise IndexError(f'Index overflow ({index} >= {self.n_outputs})')
return self._outputs[index].data
class TfliteLayerOptions:
"""Generic layer options object"""
def __init__(self, fb_object=None, type:_tflite_schema_fb.BuiltinOptions=None):
self._type = type
if fb_object is not None:
for x in vars(fb_object):
setattr(self, x, getattr(fb_object, x))
@property
def options_type(self) -> _tflite_schema_fb.BuiltinOptions:
""".tflite schema option code"""
return self._type
@property
def options_type_str(self) -> str:
""".tflite schema option as a string """
return _convert_object_value_to_string(_tflite_schema_fb.BuiltinOptions(), self._type)
def __str__(self):
return f'Type={self.options_type_str}'
[docs]class TfliteAddLayer(TfliteLayer):
"""ADD operation TfliteLayer"""
[docs] def __init__(self, fb_operation:_tflite_schema_fb.OperatorT, **kwargs):
TfliteLayer.__init__(self, fb_operation=fb_operation, **kwargs)
self._options = TfliteAddLayerOptions(fb_operation.builtinOptions)
@property
def options(self) -> TfliteAddLayerOptions:
"""Layer-specific options/config"""
return self._options
@property
def activation(self) -> str:
"""Fused activation"""
return self._options.activation_str
@property
def input1_tensor(self) -> TfliteTensor:
"""First input tensor data"""
return self._inputs[0]
@property
def input1_data(self) -> np.ndarray:
"""First input tensor data"""
return self.input1_tensor.data
@property
def input2_tensor(self) -> TfliteTensor:
"""Second input tensor data"""
return self._inputs[1]
@property
def input2_data(self) -> np.ndarray:
"""Second input tensor data"""
return self.input2_tensor.data
@property
def output_tensor(self) -> TfliteTensor:
"""Output tensor data"""
return self._outputs[0]
@property
def output_data(self) -> np.ndarray:
"""Output tensor data"""
return self.output_tensor.data
class TfliteAddLayerOptions(_tflite_schema_fb.AddOptionsT, TfliteLayerOptions):
"""Add layer options"""
def __init__(self, opts=None):
_tflite_schema_fb.AddOptionsT.__init__(self)
TfliteLayerOptions.__init__(self, opts,
type=_tflite_schema_fb.BuiltinOptions.AddOptions
)
self._activation = TfliteActivation(self.fusedActivationFunction)
@property
def activation_str(self) -> str:
"""Fused activation as a string"""
return self._activation.to_string()
@activation_str.setter
def activation_str(self, v):
self._activation = TfliteActivation(v)
@property
def activation(self) -> TfliteActivation:
"""Fused activation"""
return self._activation
@activation.setter
def activation(self, v:int):
self._activation = TfliteActivation(v)
def __str__(self):
return f'Activation:{self.activation_str}'
[docs]class TfliteConv2dLayer(TfliteLayer):
"""CONV_2D operation TfliteLayer"""
[docs] def __init__(self, fb_operation:_tflite_schema_fb.OperatorT, **kwargs):
TfliteLayer.__init__(self, fb_operation=fb_operation, **kwargs)
self._options = TfliteConv2DLayerOptions(fb_operation.builtinOptions)
filters_shape = self.filters_tensor.shape
self._kernel_size = (filters_shape[1], filters_shape[2])
self._filters = filters_shape[3]
@property
def options(self) -> TfliteConv2DLayerOptions:
"""Layer-specific options/config"""
return self._options
@property
def filters(self) -> int:
"""The number of filters"""
return self._filters
@property
def kernel_size(self) -> Tuple[int,int]:
"""Filters kernel size has height x width"""
return self._kernel_size
@property
def strides(self) -> Tuple[int,int]:
"""Kernel stride height x width"""
return (self._options.stride_height, self._options.stride_width)
@property
def padding(self) -> str:
"""Kernel padding"""
return self._options.padding_str
@property
def activation(self) -> str:
"""Fused activation"""
return self._options.activation_str
@property
def use_bias(self) -> bool:
"""Return if the layer uses a bias"""
return len(self._inputs) > 2
@property
def input_tensor(self) -> TfliteTensor:
"""Input tensor data"""
return self._inputs[0]
@property
def input_data(self) -> np.ndarray:
"""Input tensor data"""
return self.input_tensor.data
@property
def filters_tensor(self) -> TfliteTensor:
"""Filters tensor data"""
return self._inputs[1]
@property
def filters_data(self) -> np.ndarray:
"""Filters tensor data"""
return self.filters_tensor.data
@property
def bias_tensor(self) -> TfliteTensor:
"""Bias tensor data (None if no bias used)"""
return self._inputs[2] if self.use_bias else None
@property
def bias_data(self) -> np.ndarray:
"""Bias tensor data (None if no bias used)"""
return self.bias_tensor.data if self.use_bias else None
@property
def output_tensor(self) -> TfliteTensor:
"""Output tensor data"""
return self._outputs[0]
@property
def output_data(self) -> np.ndarray:
"""Output tensor data"""
return self.output_tensor.data
@property
def params(self) -> TfliteConvParams:
"""Calculated layer parameters"""
return TfliteConvParams.calculate(self)
[docs]class TfliteConv2DLayerOptions(_tflite_schema_fb.Conv2DOptionsT, TfliteLayerOptions):
"""Convolution layer options"""
[docs] def __init__(self, opts=None):
_tflite_schema_fb.Conv2DOptionsT.__init__(self)
TfliteLayerOptions.__init__(
self, opts,
type=_tflite_schema_fb.BuiltinOptions.Conv2DOptions
)
self._activation = TfliteActivation(self.fusedActivationFunction)
self._padding = TflitePadding(0 if opts is None else opts.padding)
@property
def activation_str(self) -> str:
"""Fused activation as a string"""
return self._activation.to_string()
@activation_str.setter
def activation_str(self, v):
self._activation = TfliteActivation(v)
@property
def activation(self) -> TfliteActivation:
"""Fused activation"""
return self._activation
@activation.setter
def activation(self, v:int):
self._activation = TfliteActivation(v)
@property
def padding_str(self) -> str:
"""Padding as a string"""
return self._padding.to_string()
@padding_str.setter
def padding_str(self, v):
self._padding = TflitePadding(v)
@property
def padding(self) -> TflitePadding:
"""Padding type"""
return self._padding
@padding.setter
def padding(self, v:int):
self._padding = TflitePadding(v)
@property
def stride_width(self) -> int:
"""Kernel stride width"""
return self.strideW
@stride_width.setter
def stride_width(self, v):
self.strideW = v
@property
def stride_height(self) -> int:
"""Kernel stride height"""
return self.strideH
@stride_height.setter
def stride_height(self, v):
self.strideH = v
def __str__(self):
return f'Padding:{self.padding_str} stride:{self.stride_width}x{self.stride_height} activation:{self.activation_str}'
[docs]class TfliteTransposeConvLayer(TfliteLayer):
"""TRANSPOSE_CONV operation TfliteLayer"""
[docs] def __init__(self, fb_operation:_tflite_schema_fb.OperatorT, **kwargs):
TfliteLayer.__init__(self, fb_operation=fb_operation, **kwargs)
self._options = TfliteTransposeConvLayerOptions(fb_operation.builtinOptions)
filters_shape = self.filters_tensor.shape
self._kernel_size = (filters_shape[1], filters_shape[2])
self._filters = filters_shape[1]
@property
def options(self) -> TfliteTransposeConvLayerOptions:
"""Layer-specific options/config"""
return self._options
@property
def filters(self) -> int:
"""The number of filters"""
return self._filters
@property
def kernel_size(self) -> Tuple[int,int]:
"""Filters kernel size has height x width"""
return self._kernel_size
@property
def strides(self) -> Tuple[int,int]:
"""Kernel stride height x width"""
return (self._options.stride_height, self._options.stride_width)
@property
def padding(self) -> str:
"""Kernel padding"""
return self._options.padding_str
@property
def use_bias(self) -> bool:
"""Return if the layer uses a bias"""
return len(self._inputs) > 3
@property
def input_tensor(self) -> TfliteTensor:
"""Input tensor data"""
return self._inputs[2]
@property
def input_data(self) -> np.ndarray:
"""Input tensor data"""
return self.input_tensor.data
@property
def filters_tensor(self) -> TfliteTensor:
"""Filters tensor data"""
return self._inputs[1]
@property
def filters_data(self) -> np.ndarray:
"""Filters tensor data"""
return self.filters_tensor.data
@property
def bias_tensor(self) -> TfliteTensor:
"""Bias tensor data (None if no bias used)"""
return self._inputs[3] if self.use_bias else None
@property
def bias_data(self) -> np.ndarray:
"""Bias tensor data (None if no bias used)"""
return self.bias_tensor.data if self.use_bias else None
@property
def output_tensor(self) -> TfliteTensor:
"""Output tensor data"""
return self._outputs[0]
@property
def output_data(self) -> np.ndarray:
"""Output tensor data"""
return self.output_tensor.data
@property
def params(self) -> TfliteTransposeConvParams:
"""Calculated layer parameters"""
return TfliteTransposeConvParams.calculate(self)
[docs]class TfliteTransposeConvLayerOptions(_tflite_schema_fb.TransposeConvOptionsT, TfliteLayerOptions):
"""Transpose convolution layer options"""
[docs] def __init__(self, opts=None):
_tflite_schema_fb.TransposeConvOptionsT.__init__(self)
TfliteLayerOptions.__init__(self, opts,
type=_tflite_schema_fb.BuiltinOptions.TransposeConvOptions
)
self._padding = TflitePadding(0 if opts is None else opts.padding)
@property
def stride_width(self) -> int:
"""Kernel stride width"""
return self.strideW
@stride_width.setter
def stride_width(self, v):
self.strideW = v
@property
def stride_height(self) -> int:
""""Kernel stride height"""
return self.strideH
@stride_height.setter
def stride_height(self, v):
self.strideH = v
@property
def padding_str(self) -> str:
"""Kernel padding as a string"""
return self._padding.to_string()
@padding_str.setter
def padding_str(self, v):
self._padding = TflitePadding(v)
@property
def padding(self) -> TflitePadding:
""""Kernel padding"""
return self._padding
@padding.setter
def padding(self, v:int):
self._padding = TflitePadding(v)
def __str__(self):
return f'Padding:{self.padding_str} stride:{self.stride_width}x{self.stride_height}'
[docs]class TfliteFullyConnectedLayer(TfliteLayer):
"""FULLY_CONNECT operation TfliteLayer"""
[docs] def __init__(self, fb_operation:_tflite_schema_fb.OperatorT, **kwargs):
TfliteLayer.__init__(self, fb_operation=fb_operation, **kwargs)
self._options = TfliteFullyConnectedLayerOptions(fb_operation.builtinOptions)
@property
def options(self) -> TfliteFullyConnectedLayerOptions:
"""Layer-specific options/config"""
return self._options
@property
def accumulator_depth(self) -> int:
"""Number of weights to accumulate"""
return self.weights_tensor.shape[-1]
@property
def units(self) -> int:
"""Number of neurons"""
return self.output_tensor.shape[-1]
@property
def activation(self) -> str:
"""Fused activation"""
return self._options.activation_str
@property
def use_bias(self) -> bool:
"""Return if the layer uses a bias"""
return len(self._inputs) > 2
@property
def input_tensor(self) -> TfliteTensor:
"""Input tensor data"""
return self._inputs[0]
@property
def input_data(self) -> np.ndarray:
"""Input tensor data"""
return self.input_tensor.data
@property
def weights_tensor(self) -> TfliteTensor:
"""Weights tensor data"""
return self._inputs[1]
@property
def weights_data(self) -> np.ndarray:
"""Weights tensor data"""
return self.weights_tensor.data
@property
def bias_tensor(self) -> TfliteTensor:
"""Bias tensor data (None if no bias used)"""
return self._inputs[2] if self.use_bias else None
@property
def bias_data(self) -> np.ndarray:
"""Bias tensor data (None if no bias used)"""
return self.bias_tensor.data if self.use_bias else None
@property
def output_tensor(self) -> TfliteTensor:
"""Output tensor data"""
return self._outputs[0]
@property
def output_data(self) -> np.ndarray:
"""Output tensor data"""
return self.output_tensor.data
@property
def params(self) -> TfliteFullyConnectedParams:
"""Calculated layer parameters"""
return TfliteFullyConnectedParams.calculate(self)
[docs]class TfliteFullyConnectedLayerOptions(_tflite_schema_fb.FullyConnectedOptionsT, TfliteLayerOptions):
"""Fully connection layer options"""
[docs] def __init__(self, opts=None):
_tflite_schema_fb.FullyConnectedOptionsT.__init__(self)
TfliteLayerOptions.__init__(self, opts,
type=_tflite_schema_fb.BuiltinOptions.FullyConnectedOptions
)
self._activation = TfliteActivation(self.fusedActivationFunction)
@property
def activation_str(self) -> str:
"""Fused activation as a string"""
return self._activation.to_string()
@activation_str.setter
def activation_str(self, v):
self._activation = TfliteActivation(v)
@property
def activation(self) -> TfliteActivation:
"""Fused activation"""
return self._activation
@activation.setter
def activation(self, v:int):
self._activation = TfliteActivation(v)
def __str__(self):
return f'Activation:{self.activation_str}'
[docs]class TfliteDepthwiseConv2dLayer(TfliteLayer):
"""DEPTHWISE_CONV_2D operation TfliteLayer"""
[docs] def __init__(self, fb_operation:_tflite_schema_fb.OperatorT, **kwargs):
TfliteLayer.__init__(self, fb_operation=fb_operation, **kwargs)
self._options = TfliteDepthwiseConv2DLayerOptions(fb_operation.builtinOptions)
filters_shape = self.filters_tensor.shape
self._kernel_size = (filters_shape[1], filters_shape[2])
@property
def options(self) -> TfliteDepthwiseConv2DLayerOptions:
"""Layer-specific options/config"""
return self._options
@property
def multiplier(self) -> int:
"""Depth multiplier"""
return self._options.multiplier
@property
def kernel_size(self) -> Tuple[int,int]:
"""Filters kernel size has height x width"""
return self._kernel_size
@property
def strides(self) -> Tuple[int,int]:
"""Kernel stride height x width"""
return (self._options.stride_height, self._options.stride_width)
@property
def padding(self) -> str:
"""Kernel padding"""
return self._options.padding_str
@property
def activation(self) -> str:
"""Fused activation"""
return self._options.activation_str
@property
def use_bias(self) -> bool:
"""Return if the layer uses a bias"""
return len(self._inputs) > 2
@property
def input_tensor(self) -> TfliteTensor:
"""Input tensor data"""
return self._inputs[0]
@property
def input_data(self) -> np.ndarray:
"""Input tensor data"""
return self.input_tensor.data
@property
def filters_tensor(self) -> TfliteTensor:
"""Filters tensor data"""
return self._inputs[1]
@property
def filters_data(self) -> np.ndarray:
"""Filters tensor data"""
return self.filters_tensor.data
@property
def bias_tensor(self) -> TfliteTensor:
"""Bias tensor data (None if no bias used)"""
return self._inputs[2] if self.use_bias else None
@property
def bias_data(self) -> np.ndarray:
"""Bias tensor data (None if no bias used)"""
return self.bias_tensor.data if self.use_bias else None
@property
def output_tensor(self) -> TfliteTensor:
"""Output tensor data"""
return self._outputs[0]
@property
def output_data(self) -> np.ndarray:
"""Output tensor data"""
return self.output_tensor.data
@property
def params(self) -> TfliteDepthwiseConvParams:
"""Calculated layer parameters"""
return TfliteDepthwiseConvParams.calculate(self)
[docs]class TfliteDepthwiseConv2DLayerOptions(_tflite_schema_fb.DepthwiseConv2DOptionsT, TfliteLayerOptions):
"""Depthwise Convolution options"""
[docs] def __init__(self, opts=None):
_tflite_schema_fb.DepthwiseConv2DOptionsT.__init__(self)
TfliteLayerOptions.__init__(self, opts,
type=_tflite_schema_fb.BuiltinOptions.DepthwiseConv2DOptions
)
self._activation = TfliteActivation(self.fusedActivationFunction)
self._padding = TflitePadding(0 if opts is None else opts.padding)
@property
def stride_width(self) -> int:
"""Kernel stride width"""
return self.strideW
@stride_width.setter
def stride_width(self, v):
self.strideW = v
@property
def stride_height(self) -> int:
""""Kernel stride height"""
return self.strideH
@stride_height.setter
def stride_height(self, v):
self.strideH = v
@property
def multiplier(self) -> int:
""""Depth multiplier"""
return self.depthMultiplier
@multiplier.setter
def multiplier(self, v):
self.depthMultiplier = v
@property
def activation_str(self) -> str:
"""Fused activation as a string"""
return self._activation.to_string()
@activation_str.setter
def activation_str(self, v):
self._activation = TfliteActivation(v)
@property
def activation(self) -> TfliteActivation:
"""Fused activation"""
return self._activation
@activation.setter
def activation(self, v:int):
self._activation = TfliteActivation(v)
@property
def padding_str(self) -> str:
"""Kernel padding as a string"""
return self._padding.to_string()
@padding_str.setter
def padding_str(self, v):
self._padding = TflitePadding(v)
@property
def padding(self) -> TflitePadding:
"""Kernel padding"""
return self._padding
@padding.setter
def padding(self, v:int):
self._padding = TflitePadding(v)
def __str__(self):
return f'Multiplier:{self.multiplier} padding:{self.padding_str} stride:{self.stride_width}x{self.stride_height} activation:{self.activation_str}'
[docs]class TflitePooling2dLayer(TfliteLayer):
"""AVERAGE_POOL_2D or MAX_POOL_2D operation TfliteLayer"""
[docs] def __init__(self, fb_operation:_tflite_schema_fb.OperatorT, **kwargs):
TfliteLayer.__init__(self, fb_operation=fb_operation, **kwargs)
self._options = TflitePool2DLayerOptions(fb_operation.builtinOptions)
@property
def options(self) -> TflitePool2DLayerOptions:
"""Layer-specific options/config"""
return self._options
@property
def pool_size(self) -> Tuple[int,int]:
"""Kernel size as height x width"""
return (self._options.filter_height, self._options.filter_width)
@property
def strides(self) -> Tuple[int,int]:
"""Kernel stride as height x width"""
return (self._options.stride_height, self._options.stride_width)
@property
def padding(self) -> str:
"""Kernel padding"""
return self._options.padding_str
@property
def activation(self) -> str:
"""Fused activation"""
return self._options.activation_str
@property
def input_tensor(self) -> TfliteTensor:
"""Input tensor data"""
return self._inputs[0]
@property
def input_data(self) -> np.ndarray:
"""Input tensor data"""
return self.input_tensor.data
@property
def output_tensor(self) -> TfliteTensor:
"""Output tensor data"""
return self._outputs[0]
@property
def output_data(self) -> np.ndarray:
"""Output tensor data"""
return self.output_tensor.data
@property
def params(self) -> TflitePoolParams:
"""Calculated layer parameters"""
return TflitePoolParams.calculate(self)
[docs]class TflitePool2DLayerOptions(_tflite_schema_fb.Pool2DOptionsT, TfliteLayerOptions):
"""Pooling layer options"""
[docs] def __init__(self, opts=None):
_tflite_schema_fb.Pool2DOptionsT.__init__(self)
TfliteLayerOptions.__init__(self, opts,
type=_tflite_schema_fb.BuiltinOptions.Pool2DOptions
)
self._activation = TfliteActivation(self.fusedActivationFunction)
self._padding = TflitePadding(0 if opts is None else opts.padding)
@property
def stride_width(self) -> int:
"""Filter stride width"""
return self.strideW
@stride_width.setter
def stride_width(self, v):
self.strideW = v
@property
def stride_height(self) -> int:
"""Filter stride height"""
return self.strideH
@stride_height.setter
def stride_height(self, v):
self.strideH = v
@property
def filter_width(self) -> int:
"""Filter width"""
return self.filterWidth
@filter_width.setter
def filter_width(self, v):
self.filterWidth = v
@property
def filter_height(self) -> int:
"""Filter height"""
return self.filterHeight
@filter_height.setter
def filter_height(self, v):
self.filterHeight = v
@property
def activation_str(self) -> str:
"""Fused activation as a string"""
return self._activation.to_string()
@activation_str.setter
def activation_str(self, v):
self._activation = TfliteActivation(v)
@property
def activation(self) -> TfliteActivation:
"""Fused activation"""
return self._activation
@activation.setter
def activation(self, v:int):
self._activation = TfliteActivation(v)
@property
def padding_str(self) -> str:
"""Filter padding as a string"""
return self._padding.to_string()
@padding_str.setter
def padding_str(self, v):
self._padding = TflitePadding(v)
@property
def padding(self) -> TflitePadding:
"""Filter padding"""
return self._padding
@padding.setter
def padding(self, v:int):
self._padding = TflitePadding(v)
def __str__(self):
return f'Padding:{self.padding_str} stride:{self.stride_width}x{self.stride_height} filter:{self.filter_width}x{self.filter_height} activation:{self.activation_str}'
[docs]class TfliteReshapeLayer(TfliteLayer):
"""RESHAPE operation TfliteLayer"""
[docs] def __init__(self, *args, **kwargs):
TfliteLayer.__init__(self, *args, **kwargs)
@property
def input_tensor(self) -> TfliteTensor:
"""Input tensor data"""
return self._inputs[0]
@property
def input_data(self) -> np.ndarray:
"""Input tensor data"""
return self.input_tensor.data
@property
def output_tensor(self) -> TfliteTensor:
"""Output tensor data"""
return self._outputs[0]
@property
def output_data(self) -> np.ndarray:
"""Output tensor data"""
return self.output_tensor.data
@property
def requires_copy(self) -> bool:
"""Return true if a memcpy is required, False if the reshape was done in-place"""
return self._inputs[0].index != self._outputs[0].index
@property
def n_input_elements(self) -> int:
"""Return the number of input elements"""
return self._inputs[0].shape.flat_size
[docs]class TfliteDequantizeLayer(TfliteLayer):
"""DEQUANTIZE operation TfliteLayer"""
@property
def input_tensor(self) -> TfliteTensor:
"""Input tensor data"""
return self._inputs[0]
@property
def input_data(self) -> np.ndarray:
"""Input tensor data"""
return self.input_tensor.data
@property
def output_tensor(self) -> TfliteTensor:
"""Output tensor data"""
return self._outputs[0]
@property
def output_data(self) -> np.ndarray:
"""Output tensor data"""
return self.output_tensor.data
[docs]class TfliteQuantizeLayer(TfliteLayer):
"""QUANTIZE operation TfliteLayer"""
@property
def input_tensor(self) -> TfliteTensor:
"""Input tensor data"""
return self._inputs[0]
@property
def input_data(self) -> np.ndarray:
"""Input tensor data"""
return self.input_tensor.data
@property
def output_tensor(self) -> TfliteTensor:
"""Output tensor data"""
return self._outputs[0]
@property
def output_data(self) -> np.ndarray:
"""Output tensor data"""
return self.output_tensor.data
class TfliteMulLayer(TfliteLayer):
"""MUL operation TfliteLayer"""
def __init__(self, fb_operation:_tflite_schema_fb.OperatorT, **kwargs):
TfliteLayer.__init__(self, fb_operation=fb_operation, **kwargs)
self._options = TfliteMulLayerOptions(fb_operation.builtinOptions)
@property
def options(self) -> TfliteMulLayerOptions:
"""Layer-specific options/config"""
return self._options
@property
def activation(self) -> str:
"""Fused activation"""
return self._options.activation_str
@property
def input1_tensor(self) -> TfliteTensor:
"""First input tensor data"""
return self._inputs[0]
@property
def input1_data(self) -> np.ndarray:
"""First input tensor data"""
return self.input1_tensor.data
@property
def input2_tensor(self) -> TfliteTensor:
"""Second input tensor data"""
return self._inputs[1]
@property
def input2_data(self) -> np.ndarray:
"""Second input tensor data"""
return self.input2_tensor.data
@property
def output_tensor(self) -> TfliteTensor:
"""Output tensor data"""
return self._outputs[0]
@property
def output_data(self) -> np.ndarray:
"""Output tensor data"""
return self.output_tensor.data
class TfliteMulLayerOptions(_tflite_schema_fb.MulOptionsT, TfliteLayerOptions):
"""Multiply layer options"""
def __init__(self, opts=None):
_tflite_schema_fb.MulOptionsT.__init__(self)
TfliteLayerOptions.__init__(self, opts,
type=_tflite_schema_fb.BuiltinOptions.MulOptions
)
self._activation = TfliteActivation(self.fusedActivationFunction)
@property
def activation_str(self) -> str:
"""Fused activation as a string"""
return self._activation.to_string()
@activation_str.setter
def activation_str(self, v):
self._activation = TfliteActivation(v)
@property
def activation(self) -> TfliteActivation:
"""Fused activation"""
return self._activation
@activation.setter
def activation(self, v:int):
self._activation = TfliteActivation(v)
def __str__(self):
return f'Activation:{self.activation_str}'
def _convert_object_value_to_string(obj, needle:int) -> str:
for key in dir(obj):
if getattr(obj, key) == needle:
return key.lower()
return 'None'