[LEGACY] Operation Extractor#
Danger
The code described here has been deprecated! Do not use it to avoid working with a legacy solution. It will be kept for some time to ensure backwards compatibility, but you should not use it in contemporary applications.
This guide describes a deprecated TensorFlow conversion method. The guide on the new and recommended method, using a new frontend, can be found in the Frontend Extensions article.
Model Optimizer runs specific extractor for each operation in the model during the model loading.
There are several types of Model Optimizer extractor extensions:
The generic one, which is described in this article.
The special extractor for Caffe models with Python layers. This kind of extractor is described in the Extending Model Optimizer with Caffe Python Layers guide.
Generic extension provides a generic mechanism for the operation extractor applicable for all frameworks. Model Optimizer provides the mo.front.extractor.FrontExtractorOp
class as a base class to implement the extractor. It has the extract
class method, which gets the only parameter Node
, which corresponds to the graph node to extract data from. The operation description in the original framework format is stored in the attribute pb
of the node. The extractor goal is to parse this attribute and save necessary attributes to the corresponding node of the graph. Consider the extractor for the Const
TensorFlow operation (refer to the extensions/front/tf/const_ext.py
file):
from openvino.tools.mo.front.extractor import FrontExtractorOp
from openvino.tools.mo.front.tf.extractors.utils import tf_dtype_extractor, tf_tensor_shape, tf_tensor_content
from openvino.tools.mo.ops.const import Const
class ConstExtractor(FrontExtractorOp):
# The "op" class attribute defines a type of the operation in the framework (in this case it is a TensorFlow),
# for which the extractor should be triggered.
op = 'Const'
enabled = True # The flag that indicates that this extractor is enabled.
@classmethod
def extract(cls, node): # The entry point of the extractor.
# The `node.pb` attribute stores the TensorFlow representation of the operation, which is a Protobuf message of the
# specific format. In particular, the message contains the attribute called "value" containing the description of
# the constant. The string "pb.attr["value"].tensor" is just a Python binding for Protobuf message parsing.
pb_tensor = node.pb.attr["value"].tensor
# Get the shape of the tensor from the protobuf message, using the helper function "tf_tensor_shape".
shape = tf_tensor_shape(pb_tensor.tensor_shape)
# Create a dictionary with necessary attributes.
attrs = {
'shape': shape,
# Get the tensor value, using "tf_tensor_content" helper function.
'value': tf_tensor_content(pb_tensor.dtype, shape, pb_tensor),
# Get the tensor data type, using "tf_dtype_extractor" helper function.
'data_type': tf_dtype_extractor(pb_tensor.dtype),
}
# Update the node attributes, using default attributes from the "Const" operation and attributes saved to the
# "attrs" dictionary.
Const.update_node_stat(node, attrs)
return cls.enabled
Consider another example with an extractor of the Constant
ONNX operation (refer to the extensions/front/onnx/const_ext.py
file):
from onnx import numpy_helper
from onnx.numpy_helper import to_array
from openvino.tools.mo.front.extractor import FrontExtractorOp
from openvino.tools.mo.front.onnx.extractors.utils import onnx_attr
from openvino.tools.mo.ops.const import Const
class ConstantExtractor(FrontExtractorOp):
op = 'Constant'
enabled = True
@classmethod
def extract(cls, node):
# Use "onnx_attr" helper method, which parses the Protobuf representation of the operation saved in the "node".
# Gets the value of the attribute with name "value" as "TensorProto" type (specified with a keyword "t").
pb_value = onnx_attr(node, 'value', 't')
# Use "numpy_helper.to_array()" ONNX helper method to convert "TensorProto" object to a numpy array.
value = numpy_helper.to_array(pb_value)
attrs = {
'data_type': value.dtype,
'value': value,
}
# Update the node attributes, using default attributes from the "Const" operation and attributes saved to the
# "attrs" dictionary.
Const.update_node_stat(node, attrs)
return cls.enabled
The extractors for operations from different frameworks work similarly. The only difference is in the helper methods used to parse operation attributes encoded with a framework-specific representation.
A common practice is to use update_node_stat()
method of the dedicated Op
class to update the node attributes. This method does the following:
Sets values for common attributes like
op
,type
,infer
,in_ports_count
,out_ports_count
,version
to values specific to the dedicated operation (Const
operation in this case).Uses
supported_attrs()
andbackend_attrs()
methods, defined in theOp
class to update specific node attributeIE
. The IR emitter uses the value stored in theIE
attribute to pre-process attribute values and save them to IR.Optionally sets additional attributes provided to the
update_node_stat()
function as a second parameter. Usually these attributes are parsed from the particular instance of the operation.
Note
Model Optimizer uses numpy arrays to store values and numpy arrays of np.int64
type to store shapes in the graph.